C# C多线程没有使用足够的cpu
我正在尝试加速我用C写的一个算法。我想到的第一件事是使它并行 该算法必须在数百万个2D段上运行,每个段相互独立 下面是代码:`C# C多线程没有使用足够的cpu,c#,multithreading,optimization,C#,Multithreading,Optimization,我正在尝试加速我用C写的一个算法。我想到的第一件事是使它并行 该算法必须在数百万个2D段上运行,每个段相互独立 下面是代码:` private void DoMapping(Segment[] image, CancellationToken ct, int numTasks = 3) { long time = Environment.TickCount; LaserOutput = new List<Vector3[]>();
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的原因有任何建议
我还尝试将numtask更改为4、6和8。没有重大变化
我正在考虑GC,但是我不能做很多事情来阻止它运行
编辑:
通过减少一些类的内存使用,我已经设法提高了一点cpu使用率,现在它运行了70%左右
另一方面,通过提高四叉树的树级,我获得了显著的性能改进。因为您的段之间没有需要额外同步的依赖关系,所以我建议查看任务并行库TPL。Parallel.For或Parallel.ForEach可能会让您感兴趣 要优化现有代码,有几个选项: 删除TaskCreationOptions.LongRunning。它可能会产生新的线程,这非常耗时。 创建自己的任务调度器,并为底层线程提供更高的优先级。它也可以用于实验TPL并行循环。当前,您使用的是默认线程池,其他组件可能会使用/阻止该线程池。 更新:
另请参见如何创建具有不同优先级的自定义任务计划程序。它工作得非常好,我在几个项目中使用了它。另请参阅Stephen Toub的博客。每个线程只能对单个物理核心进行utalize。也许这就是你所面临的。还有Task.WaitAlltasks;将仅在所有任务完成后继续,因此其中一些任务可能在所有任务完成之前已经完成。您需要提供一个。我们真的应该有代码,我们可以复制粘贴并运行以查看问题。理想情况下,我们也应该有一个非并行版本的代码,这样我们可以看到基本的计算是什么。不确定你的意图是什么,但你可以使它并行并检查。实现这一点的简单方法是使用并行for循环。您还可以设置处理器相关性,这同样取决于处理器核心。Enigmativity很遗憾,我不能提供一个最小的示例,因为代码在框架中运行,为了使其工作,我必须将一半的应用程序粘贴到这里。另外,我正在为一家公司开发这个应用程序,我不能分享太多的算法@Souvik otput必须是有序的,因此使用Parallel.For会使事情更加复杂,再加上创建一百万个委托的开销。然后我建议您创建异步函数任务,并在For循环中调用它们。因为您需要一个有序的for循环,所以我认为在循环的每次迭代中减少执行时间是很好的。