【问题标题】:Fastest way to read 2D matrix读取二维矩阵的最快方法
【发布时间】:2018-03-21 11:18:47
【问题描述】:

我正在使用嵌套字典来存储在启动时具有已知值的 2D 矩阵,但我发现读取速度太慢。有什么更快的吗?

更新

我不是在寻找我的代码“不工作”的任何原因。它工作正常 - 但我想知道任何让它更快的方法。下面的详细信息是为了提供上下文。

我也尝试过使用自定义类作为键来展平嵌套字典,但速度更慢。

详情

我有一个包含 500 - 7,000 个对象的列表,我需要为每个可能的组合 (250,000 - 49,000,000) 存储一个值。

每个可能的组合都有一个默认值。该值将根据对象之间的依赖关系而变化,每个对象平均有 1 个依赖关系。对于每个依赖项,将有 1 - 100 次更新。平均而言,每次更新将读取 5 次值。

因此,对于 1 个示例,我有 1,700 个对象,用于 2,890,000 种可能的组合,具有 1,900 个依赖项,意味着 9,500 - 95,000 次读取。此示例的计算时间超过 90 秒!

这是初始化代码。我对这部分很满意,因为它在不到一秒的时间内就完成了。

var allCombinations = new Dictionary<int, Dictionary<int, int>>();
foreach (var thisObject in allObjects)
{
    var comboFor1Object = new Dictionary<int, int>();
    foreach (var otherObject in allObjects)
    {
        comboFor1Object.Add(otherObject.Id, (thisObject.Id == otherObject.Id ? 0 : 100));
    }
    allCombinations.Add(thisObject.Id, comboFor1Object);
}  

这是代码的简化更新部分 - 这是非常缓慢的部分。根据 Visual Studio Performance Profiler - 它专门在第 9,10 和 11 行读取字典。这种方法占用了 75% 的时间,其中 mscorlib.ni.dll 占了 52.9%。

foreach (var myObject in myDependency.Objects)
{
    foreach (var otherObject in myMatchingObjects)
    {
        if (myObject.Id == otherObject.Id)
        {
            continue;
        }
        var existingValue = allCombinations[myObject.Id][otherObject.Id];
        var minValue = allCombinations[myObject.Id][myDependency.FromObjectId] + allCombinations[myDependency.ToObjectId][otherObject.Id] + myDependency.MinValue;
        var maxValue = allCombinations[myObject.Id][myDependency.ToObjectId] + allCombinations[myDependency.FromObjectId][otherObject.Id] -myDependency.MaxValue;
        allCombinations[myObject.Id][otherObject.Id] = Math.Max(Math.Max(existingValue, minValue), maxValue);
    }
}

【问题讨论】:

  • 您能否展示一下您的 Id、FromObjectId 和 ToObjectId 属性的代码?
  • @rs232 认为它们都只是属性(Int32)
  • 您的对象列表allObjects 有变化吗?如果没有,并且您的Id 可以映射到数组索引,请考虑使用二维数组,那肯定会更快。否则,我建议使用IdIdValueTuple(或者,如果使用更早的C# 版本,制作你自己的结构)作为键,这样你就可以删除第二层字典。
  • @dumetrulo allObjects 不会改变。每当我查询列表时,我都必须做某种 IndexOf,我会试一试。我已经尝试使用类作为键而不是元组来删除第二层字典,而且速度很慢。我以前没见过valuetuple,我也试试。谢谢!

标签: c# performance dictionary multidimensional-array profiling


【解决方案1】:

根据我对原始问题的评论,我将创建一个值类型(或者,如果您的 C#/.NET 版本支持 ValueTuple&lt;int, int&gt;,则使用它):

struct IdById
{
    public int Id1, Id2;

    public IdById(int a, int b)
    {
        Id1 = a; Id2 = b;
    }
}

这样,您的初始化代码应如下所示:

var allCombinations = new Dictionary<IdById, int>();

foreach (var thisObj in allObjects)
{
    foreach (var otherObj in allObjects)
    {
        var ids = new IdById(thisObj.Id, otherObj.Id);
        allCombinations[ids] = (ids.Id1 == ids.Id2 ? 0 : 100);
    }
}

还有你的“臭气熏天”:

foreach (var myObj in myDependency.Objects)
{
    foreach (var otherObj in myMatchingObjects)
    {
        if (myObj.Id != otherObj.Id)
        {
            var ids = new IdById(myObj.Id, otherObj.Id);
            var existingValue = allCombinations[ids];
            var minValue =
                allCombinations[new IdById(myObj.Id, myDependency.FromObjectId)] +
                allCombinations[new IdById(myDependency.ToObjectId, otherObj.Id)] +
                myDependency.MinValue;
            var maxValue =
                allCombinations[new IdById(myObj.Id, myDependency.ToObjectId)] +
                allCombinations[new IdById(myDependency.FromObjectId, otherObj.Id)] -
                myDependency.MaxValue;
            allCombinations[ids] =
                Math.Max(Math.Max(existingValue, minValue), maxValue);
        }
    }
}

这最终是否会更快是你必须测试的……

【讨论】:

  • 我已经测试过了,结构更慢 - 更慢。我覆盖了 GetHashCode() 方法,该方法加快了速度,因为 Dictionary 需要密钥的哈希值,但仍然慢了 10 倍。
  • 不幸的是,我还没有访问 c#7 的权限!不过还是期待吧。
【解决方案2】:

在 cmets 中使用 dumetrulo 建议的二维数组的速度是使用嵌套字典进行读取的两倍。不过,对任何更快的想法都持开放态度!

for (int i = 0; i < allObjects.Count; i++)
{
    //new property to record the index in the array
    allObjects[i].Index = i;
}

var allCombinations = new int[allObjects.Count, allObjects.Count];
foreach (var thisObj in allObjects)
{
    foreach (var otherObj in allObjects)
    {
        allCombinations[thisObj.Index, otherObj.Index] = (thisObj.Id == otherObj.Id ? 0 : 100);
    }
}

这使得慢代码如下:

void DoUpdates(int[,] allCombinations)
{
    .
    .
    foreach (var myObject in myDependency.Objects)
    {
        foreach (var otherObject in myMatchingObjects)
        {
            .
            .
            var existingValue = allCombinations[myObject.Index, otherObject.Index];
            .
            . 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多