[英]How to process multiple threads at once using 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等效於此模式?
Task.WaitAll
將阻塞您的主線程,直到所有其他任務完成。 那是一個可以用於處理更多請求的線程。
相反,您應該使用await Task.WhenAll
。 但是, WhenAll
沒有需要超時的重載。 可能的解決方法是將其與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
)!
您正在從線程池中獲取線程以更快地為客戶端提供服務,但是這些線程可能被用於服務更多的客戶端! 因此,您是在告訴其他客戶“請稍等,我正在集中精力先為這個人服務”。 您還將引入很多不必要的開銷。
在Web應用程序中,優良作法是一次僅使用一個線程來為客戶端提供服務,並僅將異步代碼用於異步I / O。
編輯:阿倫
.net(x86)中的每個線程使用1MB RAM或(x64)上4MB。 因此,即使是具有16GB內存的相當強大的服務器也只能運行4000個線程(假設其他地方沒有內存使用)。 這意味着,如果每個請求運行4個線程,則您只能同時處理1000個請求。
而node.js服務器(使用與ASP.Net async / await類似的模型)可以輕松地在單個線程上處理10000個並發請求(讀取更小的內存占用)。
有關更多詳細說明,請參見Stephen Cleary的Task.Run禮節示例:不要在Implementation中使用Task.Run 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.