2014-03-28 25 views
0

考慮這樣的代碼:如果完全異步,我的任務是否長時間運行?

private static async Task ProcessSomethingAsync() 
{ 
    while (true) 
    { 
     var message = await GetMessageAsync(); 
     await WriteAsync(message); 
    } 
} 

考慮到GetMessageAsyncWriteAsync方法槓桿異步IO。

想象一下,我有幾個(從2到N)這樣的任務,只要應用程序存在,它就一直存在。 我認爲,因爲循環內的代碼是完全異步的,所以最好不要在啓動這樣的任務時使用LongRunning選項,以便我們能夠利用ThreadPool而不是爲每個Task創建線程。

這是正確的還是我錯過了什麼?

+0

如果這些方法實際上是異步I/O,而不是CPU綁定,那麼它們可以在一個線程內生活得很好。當然,如果主線程沒有被佔用,但即使這樣,你也可以在另一個線程中執行所有這些。 – Luaan

+0

'GetMessageAsync()'和/或'WriteAsync()'實際上可以同步完成嗎?請記住,如果它們實際上完全同步完成,那麼'await'實際上並不代表該線程實際上將被放棄的時間點。 –

+0

@presiuslitelsnoflek同意,術語異步和長時間運行是正交的,但也許我應該改變問題更具體。 – Max

回答

5

當我啓動這樣的任務時,最好不要使用LongRunning選項,以便我們能夠利用ThreadPool而不是每個Task創建線程。

當您運行async代碼時,您不應指定LongRunning。如果你這樣做,那麼(截至今天的實現),線程池將啓動一個新線程來運行你的async代碼的第一部分。只要您的代碼在await處產生,該新線程將被處置,其餘代碼將在常規線程池線程上運行。所以,LongRunning通常適用於async的代碼。

我爲什麼StartNew is dangerous一篇博客文章中,我(暫時的)涵蓋所有TaskCreationOptions在那個崗位:

AttachedToParent不應該在異步任務中使用,所以這是的。 DenyChildAttach應該總是與異步任務一起使用(提示:如果您還不知道,那麼StartNew不是您需要的工具)。 DenyChildAttach由Task.Run傳遞。 HideScheduler可能在一些非常模糊的調度場景中很有用,但通常應避免異步任務。這隻剩下LongRunning和PreferFairness,它們都是隻應在應用程序分析後指定的優化提示。我經常看到LongRunning特別被濫用。在絕大多數情況下,線程池將在0.5秒內調整爲任何長時間運行的任務 - 而不是 LongRunning標誌。很可能,你並不需要它。

+1

有趣的是,'LongRunning'似乎啓動一個普通的線程,而不是一個池線程。 'Thread.IsThreadPoolThread'對它來說是'false'。所以即使有ThreadPool飢餓,它也會立即開始。 – Noseratio

+0

這正是我的想法。我也看到了你的文章。謝謝。 – Max

+0

@Noseratio ThreadPool適用於相對較短的代碼段,所以明確標記爲長時間運行的代碼不會在那裏運行。 – svick

1

是,指定LongRunning將可能允許創建多個線程,因爲你是在告訴你的任務是要養豬線程長一段時間的調度。

異步方法正好相反,他們釋放線程來做其他事情而不會阻塞。