我有一个包含大约1亿个非零元素的稀疏矩阵:
// [Row][Column][Element]
public IDictionary<int, IDictionary<int, decimal>> MyMatrix { get; private set; }
获取每行的总和非常快:
private void RowSum()
{
var rowTotals = new ConcurrentDictionary<int, decimal>();
Parallel.ForEach(MyMatrix, (row) =>
{
rowTotals.TryAdd(row.Key, row.Value.Sum(x => x.Value));
});
}
获取每列的总和要慢得多:
private void ColumnSum()
{
var columnTotals = new ConcurrentDictionary<int, decimal>();
Parallel.ForEach(MyMatrix, (row) =>
{
foreach (var column in row.Value)
{
columnTotals.AddOrUpdate(column.Key, column.Value,
(key, old) => old + column.Value);
}
});
}
为了更快地进行列计算,我可以创建一个[Column] [Row] [Element]矩阵,但这会使RAM需求翻倍。是否有任何方法或数据结构可以使列计算与行计算一样快,而不会使ram加倍?
答案 0 :(得分:3)
可能发生的事情是集中ConcurrentDictionary
存在争议。如果是这种情况,您可以尝试localInit
的{{1}}重载,为每个任务批处理提供自己的本地(和无竞争)Parallel.ForEach
,然后将其聚合到中心字典中结束:
Dictionary
修改
一些时间(100000 x 100000空间中的10M填充元素)
所以仍然比行总和慢一个数量级,但看起来是一个合理的改进。
(我的词典使用中也有错误)
答案 1 :(得分:1)
我认为
Parallel.ForEach(MyMatrix, (row) =>
{
foreach (var column in row.Value)
{
columnTotals.AddOrUpdate(column.Key, 0, (key, old) => old + column.Value);
}
});
应该是
Parallel.ForEach(MyMatrix, (row) =>
{
foreach (var column in row.Value)
{
columnTotals.AddOrUpdate(column.Key, column.value, (key, old) => old + column.Value);
}
});
我认为您可以通过public IDictionary<Tuple<int, int>, decimal> MyMatrix { get; private set; }
答案 2 :(得分:0)
如果最高和最低列值之间的差异足以创建一个简单的int数组,您可以按以下步骤操作:
确定最高和最低值,以进一步创建一个对应数组,该对应数组与每个列值相关联,用于对值进行求和的2个数组中的索引,即存储列值的数组,以及并行的列总计。
您的代码如下:
private void ColumnSum()
{
int highestKeyValue=int.MinValue;
int lowestKeyValue =int.MaxValue;
Parallel.ForEach(MyMatrix, (row) =>
{ // identify highest and lowest column value
foreach (var column in row.Value)
{
lowest =Math.Min(lowestKeyValue ,column.Key) ;
highest=Math.Max(highestKeyValue,column.Key) ;
}
// Create correspondence array
int[] corrrespondence=new int[highestKeyValue-lowestKeyValue];
for (int i=0;i<highest-lowest;i++) corrrespondence[i]=-1 ;
Parallel.ForEach(MyMatrix, (row) =>
{ // tag the key values found in matrix
foreach (var column in row.Value) corrrespondence[column.Key-lowest]=0 ;
}
int columnsCount=0 ;
// compute the indexes to result arrays
for (int i=0;i<highest-lowest;i++)
if (corrrespondence[i]>=0) corrrespondence[i]=columnsCount++ ;
// allocate and initialize results array
int[] columnValues=new int[columnsCount]() ;
int[] columnTotals=new int[columnsCount]() ;
for (int i=0;i<columnsCount;i++) columnTotals[i]=0 ;
Parallel.ForEach(MyMatrix, (row) =>
{
foreach (var column in row.Value)
{
int j=correspondence[column.Key-lowest] ;
// a lock on results[j] is required there to avoid concurrent update of results[j]
columnValues[j]=column.Key ;
columnTotals[j]+=column.Value ;
}
}
}