使用任务并行库进行调度

时间:2013-12-19 13:35:41

标签: c# design-patterns task-parallel-library

我必须处理大约200,000个对象(在桌面应用程序中),每个对象需要大约20毫秒来处理。为了加快这个速度,我想同时做到这一点。

对于测试我只是将每个对象放在一个单独的任务中,但由于作业的小尺寸,这只会产生很小的速度提升。所以我的第一个问题是:

是否有一种聪明(但不是太复杂)的方法来为这些对象找到最佳批量大小?我想我可以对一些本地测试是否最快将它们分组在10个,20个或100个对象中,但这似乎有点不理想。

其次(并且更重要):大多数对象只要在获得一些CPU时间时就应该被处理。但是,用户将始终查看10-20个对象。我希望始终能够将用户正在查看的对象放在队列的前面,以便提供流畅的用户体验。用户可能一直在导航,因此我觉得始终能够快速重新安排订单非常重要。 (20 ms * 20应该能够在大约0.4秒内处理完毕。)

有人可以帮我设计一个好的设计图案来处理这些物品吗?

2 个答案:

答案 0 :(得分:3)

如果对象在集合中,您可以使用Parallel.ForEach或Parallel.For。由于您的用户响应要求,Parallel.For将是更好的选择。

不幸的是,根据结果衡量绩效和调整战略是无可替代的。

答案 1 :(得分:1)

如果你想并行处理项目并且不关心顺序,只需使用Parallel.ForEach()(从后台线程调用它,这样就不会阻止UI线程)。

但是如果你想实现那种动态的优先级改变,那就更复杂了。

一种方法是拥有一个对象,我们称之为Job,它代表必须执行的单个动作。然后你会有一个处理作业队列的方法,但是如果有的话,执行那些具有高优先级的作业。类似的东西:

Queue<Job> jobs;
IEnumerable<Job> priorityJobs;

void ProcessJobs()
{
    while (true)
    {
        Job job = null;

        lock (jobs)
        {
            job = priorityJobs.FirstOrDefault(j => j.NotYetStarted);

            if (job == null)
            {
                do
                {
                    if (jobs.Count == 0)
                        return;

                    job = jobs.Dequeue();
                } while (job.NotYetStarted);
            }

            job.NotYetStarted = false;
        }

        job.Execute();
    }
}

然后,您将启动线程并行执行ProcessJobs(),例如:

var tasks = Enumerable.Range(0, Environment.ProcessorCount)
    .Select(_ => Task.Run(() => ProcessJobs()));