有些背景,我正在尝试进行大规模的建筑模拟。
问题是我有一个自定义类型Point3D
的列表,我想对它进行快速数组乘法。因此,在不同的时间步,我必须为double
Point3D
计算Point3D
值Point3D
(我已经重载了Dictionary<double,List<Point3D>>
的乘法和除法运算){{1}然后,结果将存储在public static Dictionary<double, List<Point3D>> ComputeTimeSeries(Dictionary<double, double> timeStep, List<Point3D> dofs)
{
var timeSeries = new Dictionary<double, List<Point3D>>();
foreach(var keyValue in timeStep)
{
// the point3d*double operation is already being overloaded.
timeSeries.Add(keyValue.Key, dofs.Select(pt=>pt*keyValue.Value).ToList());
}
return timeSeries;
}
中。这本词典的关键是不同的时间步长,值是相应的位移。
由于我有很多DOF,并且有很多时间步,所以上面的操作似乎很慢。无论如何都要优化整个操作?
这是我目前的代码,而且非常慢。所以我需要一些想法来优化它。
{{1}}
注意:我目前仍然坚持使用.Net 3.5。所以PLINQ和TPL可能无济于事
答案 0 :(得分:2)
我会尝试这样的事情:
public static Dictionary<double, Point3D[]> ComputeTimeSeries(Dictionary<double, double> timeStep, Point3D[] dofs)
{
var timeSeries = new Dictionary<double, Point3D[]>();
foreach(var keyValue in timeStep)
{
var tempArray = new Point3D[dofs.Length];
for (int index=0; index < dofs.Length; index++)
tempArray[index] = dofs[index] * keyValue.Value;
timeSeries.Add(keyValue.Key, tempArray);
}
return timeSeries;
}
使用Select / ToList更具可读性,但与简单的乘法相比,额外的接口调用非常昂贵。
答案 1 :(得分:1)
对于初学者,您可以在创建新词典时使用Capacity参数来消除一些重新分配和复制:
var timeSeries = new Dictionary<double, List<Point3D>>(timeStep.Count);
foreach循环中的代码看起来彼此独立,这意味着您可以并行运行它。在.NET4中,这就像替换一样简单:
foreach(var keyValue in timeStep) { ... }
与
Parallel.Foreach(timestep, key, (key) => ...);
答案 2 :(得分:1)
Profiler会给你一些想法。 另外,试着逃离linq
public static Dictionary<double, List<Point3D>> ComputeTimeSeries(Dictionary<double, double> timeStep, List<Point3D> dofs)
{
var timeSeries = new Dictionary<double, List<Point3D>>();
foreach(var keyValue in timeStep)
{
List<double> lst = new List<double>();
foreach (Point3D point in dofs)
lst.Add(point* keyValue.Value);
timeSeries.Add(keyValue.Key, lst); // the point3d*double operation is already being overloaded.
}
return timeSeries;
}
答案 3 :(得分:0)
我不是C#专家,但也许是
dofs.Select(pt=>pt*keyValue.Value).ToList()
部分可以从并行化中受益。使用SIMD
说明和/或主题,您可以并行执行dofs[0] *= keyValue.Value
和dofs[1] *= keyValue.Value
等。
此代码与Optimize Managed Code For Multi-Core Machines文章中给出的第一个示例非常相似。所以也许你可以将上面的内容重写为
Parallel.For(0, dofs.Length, delegate(int i) {
dofs[i] *= keyValue.Value;
});
答案 4 :(得分:0)
如果您可以将返回值从Dictionary<double, List<Point3D>>
更改为Dictionary<double, IEnumerable<Point3D>>
,则可以将实际计算推迟到需要时为止。
您可以移除.ToList()
并最终获得以下内容:
public static Dictionary<double, IEnumerable<Point3D>> ComputeTimeSeries(Dictionary<double, double> timeStep, List<Point3D> dofs)
{
var timeSeries = new Dictionary<double, List<Point3D>>();
foreach(var keyValue in timeStep)
{
// the point3d*double operation is already being overloaded.
timeSeries.Add(keyValue.Key, dofs.Select(pt=>pt*keyValue.Value));
}
return timeSeries;
}
现在,当您开始枚举值而不是ComputeTimeSeries方法内部时,将执行计算。这不会使计算更快,但你可能会及时将它们传播出去,甚至可能跨越许多线程。