You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在D语言中能否在运行时创建内存连续的多维数组?

D语言完全可以实现你的需求。你尝试的写法无法编译是因为int[nr][nc]属于静态数组类型,其维度必须是编译期常量,不能使用运行时变量指定。以下是两种成熟的实现方案:

方案1:自定义Array2D结构体(通用最优方案)

通过简单的结构体包装一维数组,实现[r][c]语法,无任何额外内存开销,性能等价于手动计算偏移的一维数组:

import core.memory;

struct Array2D(T) {
    private T* data;
    size_t rows; // 行数nr
    size_t cols; // 列数nc

    /// 传入行数、列数创建数组
    this(size_t nr, size_t nc) {
        rows = nr;
        cols = nc;
        data = (new T[nr * nc]).ptr;
    }

    /// 实现 arr[r][c] 索引
    T[] opIndex(size_t r) @nogc nothrow @trusted {
        // 开启边界检查可取消下一行注释
        // assert(r < rows, "行索引越界");
        return data[r * cols .. (r + 1) * cols];
    }

    /// 可选:支持 arr[r,c] 直接索引,省略中间切片生成步骤,性能更高
    ref T opIndex(size_t r, size_t c) @nogc nothrow @trusted {
        // 开启边界检查可取消下一行注释
        // assert(r < rows && c < cols, "索引越界");
        return data[r * cols + c];
    }

    /// 可选:暴露原始指针,方便对接C接口或手动操作内存
    T* ptr() @property @nogc nothrow { return data; }
}

使用示例:

void main() {
    ulong nr = 3, nc = 4;
    auto arr = Array2D!int(nr, nc);
    arr[1][2] = 42;
    assert(arr.ptr[1 * nc + 2] == 42);
}

方案2:chunks简便实现(快速开发用)

如果不想自己写结构体,可以直接用标准库std.range.chunks将一维数组按行拆分,无需额外内存开销:

import std.range;

void main() {
    ulong nr = 3, nc = 4;
    auto data = new int[nr * nc];
    auto arr = data.chunks(nc);
    arr[1][2] = 42;
    assert(data[1 * nc + 2] == 42);
}

如果需要完全兼容D的动态数组接口,可以在chunks后加.array,但会额外存储每行的指针,产生少量内存开销。


方案性能对比

以下是对10,000,000 × 20的double类型数组的实测结果,测试函数如下:

import std.math;

auto busywork(T)(T p, size_t nr, size_t nc) {
    foreach (r; 0..nr) {
        foreach (c; 0..nc) {
            p[r][c] = r + log(1.0 + c);
        }
    }
    double result = 1.0;
    foreach (t; 0..1) {
        foreach (r; 0..nr) {
            foreach (c; 0..nc) {
                result += log(1.0 + pow(p[r][c], 3));
            }
        }
    }
    return result;
}

对比的5种实现:

  • baseline:一维数组,手动使用p[r * nc + c]索引
  • baseline_dynamic:D原生二维动态数组
  • chunks_array:chunks方案加.array调用
  • chunks:chunks方案不加.array
  • array2d:上述自定义Array2D方案,关闭opIndex边界检查

运行耗时

下表为5次运行的中位数耗时,单位为毫秒:

方案dmd -Ogdc -O3gdc -Osldc -O3
baseline13592 +/- 175820978 +/- 43415452 +/- 117820778 +/- 1017
baseline_dynamic13481 +/- 33920782 +/- 50113476 +/- 20920632 +/- 156
chunks15800 +/- 14421014 +/- 17613676 +/- 11821203 +/- 212
chunksarray12903 +/- 64919648 +/- 108012895 +/- 51919770 +/- 816
array2d12606 +/- 60619844 +/- 104212640 +/- 54019724 +/- 953

内存开销

  • chunks和array2d相对于baseline无额外内存开销
  • 所有编译器下chunksarray均有9%的内存开销
  • baseline_dynamic在dmd下有18%的开销,在gcc和ldc下开销达41%
    相对开销会随数组维度和元素类型变化

结论

-O3和-Os参数的巨大性能差异,以及dmd -O编译下array2d部分运行结果性能优于baseline的现象(对汇编的检查显示dmd没有内联opIndex)表明,当数组占用系统内存比例较高时,缓存失效次数是影响性能的主导因素。设置-boundscheck=off后dmd -O编译的baseline性能与array2d持平,这就是array2d有时表现更好的原因。

chunksarray的优势是代码更短,语法和动态数组一致,当nc和/或T.sizeof足够大,相对内存开销影响较小时可以选择该方案,通用场景下array2d是最优选择。


内容的提问来源于stack exchange,提问作者Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 01:36:03