C#多线程没有使用足够的cpu

时间:2017-06-16 05:31:26

标签: c# multithreading optimization

我试图加快我用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任务更改为4,6和8 。没有重大变化。

我正在考虑使用GC,但我无法做很多事情来防止它运行。

修改  通过减少某些类的内存使用量,我已经设法提高了一点cpu的使用率,现在它运行了大约70%。

另一方面,通过提高QuadTree的级别阈值,我获得了显着的性能提升。

1 个答案:

答案 0 :(得分:4)

因为您的段之间没有需要额外同步的依赖关系,所以我建议您查看任务并行库(TPL)。 Parallel.ForParallel.ForEach对您来说可能很有趣。

要优化现有代码,有以下几种选择:

  • 删除TaskCreationOptions.LongRunning。它可能会产生新的线程,这很费时间。
  • 创建自己的任务计划程序,并为底层线程提供更高的优先级。它也可以在试验TPL并行循环时使用。目前,您正在使用默认线程池,可以由其他组件使用/阻止。

<强>更新 另请参阅lowering priority of Task.Factory.StartNew thread,了解如何使用不同的优先级创建自定义任务计划程序。它工作得很好,我用它来做几个项目。另见Stephen Toub的博客。