【发布时间】:2017-06-16 05:31:26
【问题描述】:
我正在尝试加快我用 C# 编写的算法。我想到的第一件事就是让它平行。
该算法必须运行大量(约数百万)个 2D 片段,每个片段都独立于其他片段。
这里是代码:`
private void DoMapping(Segment[] image, CancellationToken ct, int numTasks = 3)
{
long time = Environment.TickCount;
LaserOutput = new List<Vector3[]>();
NormalsOutput = new List<Vector3>();
Task< Tuple < List<Vector3[]>, List < Vector3 >>>[] tasks = new Task<Tuple<List<Vector3[]>, List<Vector3>>>[numTasks];
int perTaskSegments = image.Length / numTasks;
for (int taskIndex = 0; taskIndex < tasks.Length; taskIndex++)
{
int nseg = perTaskSegments * (taskIndex + 1) + (taskIndex == tasks.Length - 1 ? image.Length % tasks.Length : 0);
int from = perTaskSegments * taskIndex;
Tuple<int, int, Segment[], CancellationToken> obj = new Tuple<int, int, Segment[], CancellationToken>(from, nseg, image, ct);
tasks[taskIndex] = Task.Factory.StartNew(DoComputationsAction, obj, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
Task.WaitAll(tasks);
for (int taskIndex = 0; taskIndex < tasks.Length; taskIndex++)
{
LaserOutput.AddRange(tasks[taskIndex].Result.Item1);
NormalsOutput.AddRange(tasks[taskIndex].Result.Item2);
}
}
private Tuple<List<Vector3[]>, List<Vector3>> DoComputationsAction(object obj)
{
Tuple<int, int, Segment[], CancellationToken> parm = obj as Tuple<int, int, Segment[], CancellationToken>;
List<Vector3[]> tmpLaser = new List<Vector3[]>();
List<Vector3> tmpNormals = new List<Vector3>();
bool errorOccured = false;
for (int segCounter = parm.Item1; segCounter < parm.Item2 && !errorOccured; segCounter++)
{
if (parm.Item4.IsCancellationRequested)
break;
try
{
var res = SplitOverMap(parm.Item3[segCounter], (string error) => {
errorOccured = true;
MessageBox.Show(error, "An error occured", MessageBoxButtons.OK, MessageBoxIcon.Error);
Logger.Log("An error occured while mapping data to 3d.");
});
if (res != null)
{
tmpLaser.AddRange(res.Item1);
tmpNormals.AddRange(res.Item2);
}
}
catch (Exception e)
{
Logger.Log("An error occured while calculating 3d map. Skipping polyline." + e.Message);
}
}
return new Tuple<List<Vector3[]>, List<Vector3>>(tmpLaser, tmpNormals);
}`
在 SplitOverMap 内部,执行 对空间数据结构 (QTree) 的查询,然后进行一些计算。
没有锁在整个过程中被执行。 未使用磁盘。
您对导致 cpu 使用率仅达到 40-60 的原因有什么建议吗?
我也尝试将 num task 更改为 4、6 和 8。没有大的变化。
我正在考虑 GC,但我无法阻止它运行。
编辑: 通过减少一些类的内存使用,我设法稍微提高了 CPU 使用率,现在它运行在 70% 左右。
另一方面,通过提高四叉树的水平阈值,我获得了实质性的性能提升。
【问题讨论】:
-
每个单线程只能使用一个物理核心。也许这就是你所面临的。此外
Task.WaitAll(tasks);只会在所有任务完成后继续,因此其中一些可能在所有任务完成之前已经完成。 -
您需要提供minimal reproducible example。我们真的应该有可以复制粘贴并运行以查看问题的代码。理想情况下,我们也应该有此代码的非并行版本,以便我们可以看到基本计算是什么。
-
不确定你的意图是什么,但你可以让它平行并检查。简单的方法是使用 Parallel for 循环。您还可以设置再次依赖于处理器内核的处理器亲和性。
-
Enigmativity 不幸的是,我无法为您提供一个最小的示例,因为代码在框架中运行并且要使其正常工作,我必须在此处粘贴一半的应用程序。另外我正在为一家公司开发这个应用程序,我不能分享太多的算法。 @Souvik 必须对 otput 进行排序,因此使用 Parallel.For 会使事情变得更加复杂,而且还会产生创建一百万个委托的开销。
-
那么我建议你创建异步函数任务并在for循环中调用它们。由于您需要一个有序的 for 循环,我认为最好减少循环的每次迭代中的执行时间。
标签: c# multithreading optimization