【问题标题】:C# is slow on arrays? [closed]C# 在数组上很慢? [关闭]
【发布时间】:2015-03-28 14:11:46
【问题描述】:

我正在处理 CT 图像,因此需要大量操作 3D 数组,但发现 C# 处理数组非常慢。我写了一个简单的 BFS 测试,基于https://stackoverflow.com/a/1056091:

struct Vector
{
    public int X, Y, Z;
}
int width = 512, height = 512, depth = 200;
public static int bfs(int[, ,] matrix)
{
    bool[, ,] visited = new bool[width, height, depth];
    int sum = 0;
    Queue<Vector> queue = new Queue<Vector>();
    queue.Enqueue(new Vector { X = 0, Y = 0, Z = 0 });
    while (queue.Count > 0)
    {
        Vector c = queue.Dequeue();
        int cx = c.X;
        int cy = c.Y;
        int cz = c.Z;
        sum += matrix[cx, cy, cz];
        int x, y, z;

        if ((x = cx - 1) >= 0 && !visited[x, cy, cz])
        { queue.Enqueue(new Vector { X = x, Y = cy, Z = cz }); visited[x, cy, cz] = true; }
        if ((y = cy - 1) >= 0 && !visited[cx, y, cz])
        { queue.Enqueue(new Vector { X = cx, Y = y, Z = cz }); visited[cx, y, cz] = true; }
        if ((z = cz - 1) >= 0 && !visited[cx, cy, z])
        { queue.Enqueue(new Vector { X = cx, Y = cy, Z = z }); visited[cx, cy, z] = true; }
        if ((x = cx + 1) < width && !visited[x, cy, cz])
        { queue.Enqueue(new Vector { X = x, Y = cy, Z = cz }); visited[x, cy, cz] = true; }
        if ((y = cy + 1) < height && !visited[cx, y, cz])
        { queue.Enqueue(new Vector { X = cx, Y = y, Z = cz }); visited[cx, y, cz] = true; }
        if ((z = cz + 1) < depth && !visited[cx, cy, z])
        { queue.Enqueue(new Vector { X = cx, Y = cy, Z = z }); visited[cx, cy, z] = true; }
    }
    return sum;
}
public static void TestTime<T, TR>(Func<T, TR> action, T obj, int iterations)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    for (int i = 0; i < iterations; ++i)
        action(obj);
    Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed);
}
static void Main(string[] args)
{
    Random random = new Random();
    int[, ,] m1 = new int[width, height, depth];
    for (int x = 0; x < width; ++x)
        for (int y = 0; y < height; ++y)
            for (int z = 0; z < depth; ++z)
                m1[x, y, z] = random.Next();
    const int iterations = 1;
    TestTime<int[, ,], int>(bfs, m1, iterations);
    TestTime<int[, ,], int>(bfs, m1, iterations);
}

这需要大约 23 秒(一次迭代)。用VS2012编译,“Release”d,优化。尝试编写类似的 C++ 代码(使用堆栈分配的数组),大约需要 0.08 秒。 DFS(使用堆栈而不是队列)运行速度较慢。一维或锯齿状阵列给出几乎相同的结果。 我应该注意到连续访问(如Why are multi-dimensional arrays in .NET slower than normal arrays?)运行良好,[512x512x200] 数组的 100 次迭代在 ~26 秒内。

为什么在 C# 中非连续数组访问如此缓慢?有什么办法可以加快速度吗?

【问题讨论】:

  • 在分析器中运行,看看是否发现了任何“热点”区域。
  • 您似乎将分配以及队列和数组一起测量。如果你只为数组访问编写基准会发生什么?
  • 250x 的差异应该会让你非常怀疑。您的基准完全无效。
  • 您的 C++ 和 C# 代码完全不同。在 C++ 中,您有一个带有元组的队列。为什么不在 C# 中做同样的事情?

标签: c# .net arrays performance


【解决方案1】:

我改用 list+struct 看看是否有帮助。它把时间减半。我将多维数组更改为使用单维并手动将索引器相乘。如果有的话,那就更糟了。

struct Q
{
    public int X, Y, Z;
}
public static int bfs(int[, ,] matrix)
{
    int d1 = matrix.GetLength(0), d2 = matrix.GetLength(1), d3 = matrix.GetLength(2);
    var visited = new bool[d1, d2, d3];
    int sum = 0;
    var q = new List<Q>();
    q.Add(new Q());
    while (q.Count > 0)
    {
        var last = q[q.Count - 1];
        q.RemoveAt(q.Count - 1);
        int cx = last.X;
        int cy = last.Y;
        int cz = last.Z;
        sum += matrix[cx, cy, cz];
        int x, y, z;

        if ((x = cx - 1) >= 0 && !visited[x, cy, cz])
        { q.Add(new Q{X = x, Y = cy, Z = cz}); visited[x, cy, cz] = true; 
...

【讨论】:

  • 我承认使用 struct 应该会更好,但我想要至少 100 倍的加速 :)
  • 顺便说一句,你的 List 是在模仿 Stack,所以它的 DFS。 DFS 更糟糕(确认这是阵列访问的问题)。将堆栈更改为列表没有时间影响
  • 我用 struct 尝试了我的代码,结果更糟。但由于抱怨,我会更新我的问题
猜你喜欢
  • 1970-01-01
  • 2019-01-13
  • 2011-03-13
  • 2018-06-12
  • 2015-12-02
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 2023-04-06
相关资源
最近更新 更多