如何使用任务并行库一次处理多个线程

时间:2014-07-22 09:47:18

标签: c# multithreading task-parallel-library

我正在使用Asp.Net 4.0。

我还有一个HashSet,我想从中创建并异步运行任务,等待它们全部完成并应用超时。下面的代码是我到目前为止的代码,但鉴于有很多方法可以使用TPL来修饰猫,可以改进,还是有任何关键问题?

        TaskWrapper[] taskWrappers = new TaskWrapper[nodeCount];
        Task<ResponseWrapper>[] tasks = new Task<ResponseWrapper>[nodeCount];

        int i = 0;
        foreach (var n in rt.Nodes)
        {
            tasks[i] = Task<ResponseWrapper>.Factory.StartNew(() => MyMethod.Submit(n.Data, timeout));

            taskWrappers[i].LeadPointID = n.LeadPointID;
            // other wrapper stuff;
            taskWrappers[i].Task = tasks[i];

            i++;
        }

        Task.WaitAll(tasks, timeout);

阅读了所提供的文章后,似乎这种代码结构将成为首选的工作方式:

class MyService2
{
    public int CalculateMandelbrot()
    {
        // Tons of work to do in here!
        for (int i = 0; i != 10000000; ++i)
            ;
        return 42;
    }
}

private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(() => myService.CalculateMandelbrot());
}

然而,正如我之前所指出的那样,我无法访问VS2012,所以作为一个起点,是否存在与此模式相当的VS2010?

1 个答案:

答案 0 :(得分:2)

Task.WaitAll将阻止您的主线程,直到所有其他任务完成。这可以用于服务更多请求的一个较少的线程。

相反,您应该使用await Task.WhenAll。但是,WhenAll没有超时的超时。 A possible workaround是将它与Task.Delay结合使用,然后等待所有任务完成或延迟任务完成:

await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));

如果您无法访问VS 2012,那么另一种方法是将延续任务附加到WhenAny,然后返回该任务。该框架将负责其余部分。

public Task<string> Post()
{
    var tasks = //...
    var continuation = Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout))
                           .ContinueWith(whenAnyTask => 
        {
             //the rest of your code
             return "Hello";
        };

    return continuation;
}

更重要的是:不要在ASP.NET应用程序上使用Task.Run(或StartNew)!

您正在从线程池中获取线程以更快地为客户端提供服务,但这些线程可用于为更多客户端提供服务!因此,您要告诉其他客户&#34;等一下,我首先将我的资源集中在为这个人服务上#34;你也引入了很多不必要的开销。

在Web应用程序中,一次只使用一个线程来为客户端提供服务,并且仅将异步代码用于异步I / O,这是一种很好的做法。


编辑:Aron

.net(x86)中的每个线程使用1MB RAM或4MB(x64)。即使是具有16GB内存的相当强大的服务器也只能运行4000个线程(假设其他地方没有内存使用)。这意味着如果每个请求运行4个线程,则只能同时处理1000个请求。

而node.js服务器(使用与ASP.Net async / await类似的模型)可以轻松地在单个线程上处理超过10000个并发请求(读取更小的内存占用量)。


有关更详细的说明,请参阅Stephen Cleary的Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation