比较c#,c++和Java的性能(c#的奇怪行为)

Comparing c# , c++ and java performance ( Strange behavior of c# )

本文关键字:性能 c++ Java 比较      更新时间:2023-10-16

我正在用C++,C#和Java实现Floyd-Warshall算法。 在每种语言中,我使用顺序和并行实现 测试后结果是:
(运行时间仅适用于主函数和读取文件,变量的Inti和...不测量。
在此处下载源代码

C++

  • IDE:Netbeans
  • 编译器:MinGW-4.8.1
  • 顺序时间 : 9.333000
  • 并行时间 : 2.539000
  • OpenMp用于普拉莱尔

如果 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
  • import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Future;

爪哇变量

 public final int numNodes =1000;
    public final double[][] costs= new double[numNodes][numNodes] ;

我没有把Java代码放在这里,因为它工作正常(我认为)

C#

  1. IDE:Visual Studio 2012
  2. 编译器:Visual Studio 2012 默认
  3. 顺序时间 : 31.312
  4. 并行时间 : 8.920
  5. 使用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) => { });
    }

确定它是否是数组边界检查,或者至少确定数组边界检查是否是问题的一部分的一种方法是删除一些索引计算。例如:

    static void floyd_warshallSingle()
    {
        int i, j, k;
        for (k = 0; k < n; ++k)
        {
            var distk = dist[k];
            for (i = 0; i < n; ++i)
            {
                var disti = dist[i];
                for (j = 0; j < n; ++j)
                    if ((i != j) && (disti[k] * distk[j] != 0))
                        if ((disti[j] == 0) || disti[k] + distk[j] < disti[j])
                            disti[j] = disti[k] + distk[j];
            }
        }
    }

在这里,我所做的只是使用 distk 作为dist[k]的参考。我怀疑编译器已经在进行优化,这可能是您实现从矩形数组到交错数组时获得的性能提升的方式。但值得一试。

另外,您说您在未附加调试器的情况下运行。我假设您也在运行发布版本?所有三个程序(C++,Java和C#)是否运行相同的位数?也就是说,它们都是 64 位可执行文件吗?所有 32 位可执行文件?小心使用 C#,因为可以在项目选项中打开"首选 32 位"标志。这可能会导致您在使用"任何 CPU"进行编译时以 32 位模式运行,即使在 64 位系统上也是如此。