我必须处理大约200,000个对象(在桌面应用程序中),每个对象需要大约20毫秒来处理。为了加快这个速度,我想同时做到这一点。
对于测试我只是将每个对象放在一个单独的任务中,但由于作业的小尺寸,这只会产生很小的速度提升。所以我的第一个问题是:
是否有一种聪明(但不是太复杂)的方法来为这些对象找到最佳批量大小?我想我可以对一些本地测试是否最快将它们分组在10个,20个或100个对象中,但这似乎有点不理想。
其次(并且更重要):大多数对象只要在获得一些CPU时间时就应该被处理。但是,用户将始终查看10-20个对象。我希望始终能够将用户正在查看的对象放在队列的前面,以便提供流畅的用户体验。用户可能一直在导航,因此我觉得始终能够快速重新安排订单非常重要。 (20 ms * 20应该能够在大约0.4秒内处理完毕。)
有人可以帮我设计一个好的设计图案来处理这些物品吗?
答案 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()));