2017-07-24 38 views
2

我正在嘗試調試多線程似乎失速的多線程應用程序,然後繼續工作幾分鐘或以後再也不再。線程在調試器中的標識線

我確定他們之間存在一個爭用點,這是造成這一點,但我不知道如何找到它。在Visual Studio中使用Parallel StacksThreads視圖僅向我提供線程啓動位置的堆棧,而不是它們當前的位置。

我開始我的任務有:

Task task = new Task((object state) => { DoWork(state).GetAwaiter().GetResult(); }, $"worker_task{i}", TaskCreationOptions.LongRunning); 

然後,他們通過從ConcurrentQueue拉項目,並處理它們的進程中運行。我使用GetAwaiter().GetResult();,否則他們調用的異步方法會立即返回,即使仍在執行任務,任務也會顯示爲完成。

的Visual Studio調試窗口:

enter image description here

線程#38880實際上並沒有做任何工作,我想找出它被卡住,但它只能說明我在哪裏任務開始了。

如何查看當前任務/線程在哪一行?我是否以我看不見的方式開始我的任務?如果是這樣,我該怎麼做?


語境:我正在運行通過調用Httpclient API的任務。由於網絡延遲,我正在並行運行多個任務,以便在等待時間內最大限度地提高CPU利用率。調用HttpClient是一個異步操作,我似乎無法創建一個任務,所以我最終創建了一個匿名函數並在其中進行了阻止。

這可能是錯誤的方法,但我不知道該怎麼辦。

方法啓動的任務:

private static void InitWorkers() 
    { 
     for(int i = 0; i < max_workers; i++) 
     { 
      Task task = new Task((object state) => { DoWork(state).GetAwaiter().GetResult(); }, $"worker_task{i}", TaskCreationOptions.LongRunning); 

      ProcessingTasks.TryAdd($"worker_task{i}", task); 
      processedStats.TryAdd($"worker_task{i}", new Stat()); 

      task.Start(); 
     } 
    } 
+3

如果您使用異步方法,爲什麼不使用'await'或'Task.ContinueWith()'來代替?我有一種感覺,'GetResult()'會阻擋你,但很難從那個截圖中確定。 – xxbbcc

+0

@xxbbcc可能是因爲我是C#中的多線程新手。我想我正在犯很多天真的錯誤。這些任務長時間運行,並且正在對'HttpClient'進行異步調用,我正在並行處理多個任務。爲上下文添加mroe代碼 –

+3

@DouglasGaskell:是;您應該瞭解更多關於'async'如何工作的信息。 Stephen Cleary有很多很好的博客文章。 https://msdn.microsoft.com/en-us/magazine/jj991977.aspx – SLaks

回答

3

你的問題是.GetAwaiter().GetResult(),其中阻塞調用線程在等待任務完成。
不要這樣做。

如果您的方法是真正的異步,則根本不需要創建Task;你可以調用它,它會異步地完成它的工作。

如果它在其同步部分執行阻塞或CPU綁定調用,則應該使用Task.Run()在後臺線程中運行它並等待所產生的任務。

+0

我正在使用任務,因爲我並行運行了多個進程,這些進程調用Web服務並最終等待響應,這些進程長時間運行(小時/天)。它們是異步的,因爲'HttpClient'異步運行它的請求。如何與任務並行運行異步方法?我是否完全錯誤? –

+0

@DouglasGaskell:這些方法已經是異步的。你可以「等待」他們;你不需要做任何事情。 – SLaks

+0

這不就是說我一次只能跑1次嗎?如果我想一次等待10個HttpRequest,我想我需要運行10個並行任務。如果我「等待」一個「HttpClient」調用,它只是等待它返回,然後進入下一個,一次運行10個。 –