Dim*_*iev 15 c# multithreading grasshopper rhino3d
我正在尝试在名为Grasshopper(Rhino3D的一部分)的包中使用C#.net优化一些数学运算.操作非常简单,但必须执行的列表很大,可能会变得更大.
我在我的C#脚本中使用Parallel.ForEach和列表,我得到的最终结果数低于预期.这很可能是因为list.add不是线程安全的(或者我正在构建它的软件中没有线程安全).
private void RunScript(double z, int x, List<double> y, ref object A)
{
List<double> temp = new List<double>();
double r;
System.Threading.Tasks.Parallel.ForEach(y, numb =>
{
r = Math.Pow((numb * x), z);
temp.Add(r);
});
A = temp;
Run Code Online (Sandbox Code Playgroud)
请帮我找出一种使用CPU多线程在数百个值上运行这个简单数学运算的简单有效的方法(或者如果你有关于GPU CUDA的建议).
我希望这个模糊不清的软件不会打扰你,因为据我所知,它的表现与普通的C#.Net/Python/VB.Net完全相同.
Pet*_*iho 15
你猜对了,List<T>不是线程安全的.您必须同步对其任何实例的访问.
一种选择是简单地在每个任务中同步:
private void RunScript(double z, int x, List<double> y, ref object A)
{
List<double> temp = new List<double>();
object l = new object();
System.Threading.Tasks.Parallel.ForEach(y, numb =>
{
double r = Math.Pow((numb * x), z);
lock (l) temp.Add(r);
});
A = temp;
}
Run Code Online (Sandbox Code Playgroud)
注意:您的代码中还有另一个错误.您r在所有任务中共享相同的变量,这可能导致相同的值被添加两次或更多次到结果,而其他值被省略.我通过简单地将变量声明移动到用于ForEach()调用的匿名方法的主体来修复错误.
另一个选择是识别您事先知道您将获得多少结果,因此可以简单地初始化一个足够大的数组以包含所有结果:
private void RunScript(double z, int x, List<double> y, ref object A)
{
double[] results = new double[y.Count];
System.Threading.Tasks.Parallel.For(0, y.Count, i =>
{
// read-only access of `y` is thread-safe:
results[i] = Math.Pow((y[i] * x), z);
});
A = new List<double>(results);
}
Run Code Online (Sandbox Code Playgroud)
没有两个线程会尝试访问results数组中的相同元素,并且数组本身永远不会更改(即重新分配),因此这是完全线程安全的.
以上假设您确实需要a List<double>作为输出对象.当然,如果一个数组是令人满意的,那么你可以只分配results给A而不是将它传递给List<T>构造函数来在最后创建一个全新的对象.
一个更简单的解决方案可能是使用.AsParallel()和处理结果ParallelEnumerable:
private void RunScript(double z, int x, List<double> y, ref object A)
{
A = y
.AsParallel().AsOrdered()
.Select(elem => Math.Pow((elem * x), z))
.ToList();
}
Run Code Online (Sandbox Code Playgroud)