【发布时间】:2014-11-22 16:26:39
【问题描述】:
我正在使用 c++、c# 和 java 实现 Floyd–Warshall 算法。在每种语言中,我在测试结果后都使用顺序和并行实现:
(经过的时间仅用于主要功能和读取文件,变量的 Inti 和 ... 未测量。)在此处下载源代码SourceCodes
c++
- IDE:Netbeans
- 编译器:MinGW-4.8.1
- 连续时间:9.333000
- 并行时间:2.539000
- 将
OpenMp用于Prallel
如果
NumOfThreads=1 那么是顺序的,否则是并行的
变量
#define n 1000 /* Then number of nodes */
double dist[n][n];
void floyd_warshall(int NumOfThreads) {
int i, j, k;
omp_set_num_threads(NumOfThreads);
for (k = 0; k < n; ++k)
#pragma omp parallel for private(i,j)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][k] + dist[k][j] < dist[i][j]) || (dist[i][j] == 0))
dist[i][j] = dist[i][k] + dist[k][j]; }
java
- IDE:Netbeans
- 编译器:Netbeans 默认
- 连续时间:11.632
- 并行时间:3.089
- -Xms512m -Xmx1024m
- 导入 java.util.concurrent.Callable;
导入 java.util.concurrent.ExecutionException;
导入 java.util.concurrent.ExecutorService;
导入 java.util.concurrent.Future;
java变量
public final int numNodes =1000;
public final double[][] costs= new double[numNodes][numNodes] ;
我没有把 java 代码放在这里,因为它工作正常(我认为)
c#
- IDE:Visual Studio 2012
- 编译器:Visual Studio 2012 默认
- 连续时间:31.312
- 并行时间:8.920
- 使用 System.Threading.Tasks;
变量
const int n = 1000;
static double[,] dist = new double[n, n];
并行代码
static void floyd_warshall(ParallelOptions pOp)
{
int k;
for (k = 0; k < n; ++k)
Parallel.For<int>(0, n, pOp, () => 0, (i, loop, j) =>
{
for (j = 0; j < n; ++j)
if ((dist[i, k] * dist[k, j] != 0) && (i != j))
if ((dist[i, k] + dist[k, j] < dist[i, j]) || (dist[i, j] == 0))
dist[i, j] = dist[i, k] + dist[k, j];
return 0;
}, (j) => { });
单码
static void floyd_warshallSingle()
{
int i, j, k;
for (k = 0; k < n; ++k)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i,k] * dist[k,j] != 0) && (i != j))
if ((dist[i,k] + dist[k,j] < dist[i,j]) || (dist[i,j] == 0))
dist[i,j] = dist[i,k] + dist[k,j];
}
我的 c# 实现有什么问题?
都使用同一个文件
现在我的问题是为什么用 c# 解决这个算法需要更多时间?
java 和 c++ 的运行时间几乎相同,但我认为我使用 c# 的实现是错误的,因为 c# 和 c++ 之间的这种差异很奇怪!
请帮助我改进我的 C# 实现或说出一些原因谢谢!
编辑 1
我将数组更改为锯齿状数组,结果更改为:
- 连续时间:19.22
- 并行时间:4.903
在 c# 和 c++ 或 java 之间仍然存在巨大差异!知道为什么吗?
新变量
const int n = 1000;
static double[][] dist = new double[n][];
新代码:
static void floyd_warshallSingle()
{
int i, j, k;
for (k = 0; k < n; ++k)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][k] + dist[k][j] < dist[i][j]) || (dist[i][j] == 0))
dist[i][j] = dist[i][k] + dist[k][j];
}
static void floyd_warshall(ParallelOptions pOp)
{
int k;
for (k = 0; k < n; ++k)
Parallel.For<int>(0, n, pOp, () => 0, (i, loop, j) =>
{
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][ k] + dist[k][j] < dist[i][ j]) || (dist[i][j] == 0))
dist[i][ j] = dist[i][k] + dist[k][j];
return 0;
}, (j) => { });
}
【问题讨论】:
-
您在 C++ 和 Java 中使用锯齿状数组,但在 C# 中使用二维数组。后者在某些情况下速度较慢。尝试将您的 C# 实现也转换为锯齿状数组。
-
为了消除混淆:在 C# 中有
int[][](int[]的数组)和int[,](平面内存分配)——前者通常被称为锯齿状。int[][]在 C# 中显然比int[,]更快的事实只是意味着编译器/CLR 在某个地方做得很糟糕。在线性访问的情况下,两者的速度应该差不多,但是如果你对锯齿状数组进行随机访问,你会得到第二次缓存未命中,这是可以避免的。但是,锯齿状数组没有理由比平面数组更快。 -
另一个问题可能是操作顺序。 C# 有严格的从左到右的规则。所以对于
if ((dist[i,k] * dist[k,j] != 0) && (i != j)),乘法总是完成。 C++ 编译器(我不了解 Java)可能会生成代码来首先执行i != j测试,这会更快。以下if语句也是如此:将(dist[i,j] == 0)测试放在首位。 -
你为什么用乘法测试 !=0?不会检查双方 !=0 是否相等并保存乘法>
-
您遇到的一个问题(正如我在博客文章中指出的那样)是数组边界检查。在 C# 中,每个索引都会根据数组的边界进行检查。这将对运行时间产生影响。不过,我不希望它是双倍的。
标签: java c# c++ multithreading netbeans