【问题标题】:How to implement multi-threading and parallel execute several tasks?如何实现多线程并行执行多个任务?
【发布时间】:2013-08-14 09:05:31
【问题描述】:

我是线程编程的新手。我必须在 PARALLEL 和后台运行一些任务(以便主 UI 执行线程保持对用户操作的响应)并等待每个任务完成,然后再继续执行。

类似:

foreach(MyTask t in myTasks)
{
  t.DoSomethinginBackground(); // There could be n number of task, to save 
                               // processing time I wish to run each of them 
                               // in parallel
}

// Wait till all tasks complete doing something parallel in background


Console.Write("All tasks Completed. Now we can do further processing");

我知道有几种方法可以实现这一点。但我正在寻找在 .Net 4.0 (C#) 中实现的最佳解决方案。

【问题讨论】:

  • 你如何实现 MyTask?
  • 好吧,MyTask 可以是任何东西。在这里没关系。在我的实际解决方案中,我有一个 URL 数组,我必须为每个 URL 获取 HTML(Web Scrapping)。

标签: c# multithreading parallel-processing


【解决方案1】:

对我来说,您似乎想要Parallel.ForEach

Parallel.ForEach(myTasks, t => t.DoSomethingInBackground());

Console.Write("All tasks Completed. Now we can do further processing");

您还可以在一个循环中执行多个任务

List<string> results = new List<string>(myTasks.Count);
Parallel.ForEach(myTasks, t =>
{
    string result = t.DoSomethingInBackground();
    lock (results)
    { // lock the list to avoid race conditions
        results.Add(result);
    }
});

为了让主 UI 线程保持响应,您需要使用 BackgroundWorker 并订阅其 DoWorkRunWorkerCompleted 事件,然后调用

worker.RunWorkerAsync();
worker.RunWorkerAsync(argument); // argument is an object

【讨论】:

  • 感谢 Nolonar,到目前为止似乎是一个很好的解决方案。但是,如果每个任务都返回一个值(比如字符串值)并且我必须在继续之前合并每个任务的返回字符串怎么办?换句话说,每个任务是否可以在完成时返回值,而其他任务仍然很忙?
  • Nolonar,第二个代码块对我来说似乎是一个不错的解决方案。为了在后台运行任务,我可以将 BackgroundWorker 与 PLINQ 一起使用吗?
  • @Aakash 我不确定您将 BackgroundWorker 与 PLINQ 一起使用是什么意思。您可以在inside BackgroundWorker 中使用 PLINQ,如果这是您所要求的。
  • 是的,这正是我的意思。我创建了一个 BackGroundWorker 实例,并在 DoWork() 方法中使用 PLINQ 并行运行每个任务。每个任务都返回一个字符串集合,我使用 AddRange() 方法将其存储在一个全局字符串集合中。
  • 想知道 DoWork 是否可以将值作为参数发送到 RunWorkerCompleted 事件。就像我在 DoWork 中声明一个局部变量并在 RunWorkerCompleted 中传递它一样?
【解决方案2】:

可以使用Task库来完成:

 string[] urls = ...;
 var tasks = urls.Select(url => Task.Factory.StartNew(() => DoSomething(url)));

为避免锁定 UI 线程,您可以在 .NET 4.0 中使用ContinueWhenAll

Task.Factory.ContinueWhenAll(tasks.ToArray(), _ => 
    Console.Write("All tasks Completed. Now we can do further processing");
);

如果您使用的是最新版本的 .NET,则可以改用 Task.WhenAll

【讨论】:

  • 我仍然认为第二个代码块应该在除 Main 之外的其他线程上运行。
【解决方案3】:

如果您使用 Net 4.0 或更高版本,请参阅 Parallel 类和 Task 类。 Joseph Albahari 写了一本非常清楚的书:http://www.albahari.com/threading/part5.aspx#_Creating_and_Starting_Tasks

【讨论】:

  • 谢谢 Huy,肯定会的,看来是时候深入研究多线程了。迟早有人必须这样做。 ;-)
猜你喜欢
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多