2016-01-13 100 views
-1

幾個小時我在C#中的異步代碼掙扎,我真的不明白爲什麼我的代碼死鎖。 到目前爲止,我已經紅了很多文章,任何東西都爲我敲響了鐘聲。C#異步HttpWebRequest死鎖

希望你能幫助我。

這是我試圖運行的代碼。

主要

Task.Run(async() => 
    { 
     Task<EventDetailed[]> events = getDetailedEvents(); 
     await events; 
    }).Wait(); 

getDetailedEvents:

static async Task<EventDetailed[]> getDetailedEvents() 
     { 
      ... 
      EventDetailed[] result = await LoadDetailedEventsDetailsAsync(evnts).ConfigureAwait(false); 

      return result; 
     } 

我的問題的核心。

LoadDetailedEventsDetailsAsync

async static Task<EventDetailed[]> LoadDetailedEventsDetailsAsync(Event[] events) 
     { 
      List<EventDetailed> detailed = new List<EventDetailed>(); 
      List<Task<WebResponse>> responses = new List<Task<WebResponse>>(); 
      List<Event> tasksWithStream = new List<Event>(); 
      foreach (Event e in events) 
      { 
       var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://..."); 
       ... some headers etc ... 
       e.Stream = httpWebRequest.GetRequestStreamAsync(); 
       e.WebRequest = httpWebRequest; 
       tasksWithStream.Add(e); 
      } 
      foreach (var tsk in tasksWithStream) 
      { 

       try { 
        await tsk.Stream.ConfigureAwait(false); 
        using (var streamWriter = new StreamWriter(tsk.Stream.Result)) 
        { 
         streamWriter.Write("..."); 
         streamWriter.Flush(); 
         streamWriter.Close(); 
        } 
        responses.Add(tsk.WebRequest.GetResponseAsync()); 
       } 
       catch (Exception ex) 
       { 
        Logger.mes("Failed to get event data."); 
       } 
      } 
      foreach (var response in responses) 
      { 
       try 
       { 
        await response.ConfigureAwait(false); 
       } 
       catch (Exception ex) 
       { 
        Logger.mes("Failed to get event data."); 
        continue; 
       } 
       parseData.Add(ParseData(response)); 
      } 
+0

什麼類型的應用程序是什麼?控制檯應用程序? WPF? Windows窗體? –

+0

'Event'類是怎麼樣的?具體來說,「Event.Stream」的定義是什麼? –

+0

不要在'getDetailedEvents'上「等待」。由於你在狀態機上調用了'Wait',它會死鎖。 –

回答

1

有幾點: - 你應該使用await代替

首先,需要注意的是,你應該幾乎從未呼籲異步任務.Wait(或.Result)是很重要的。其中一個非常有幾個例外是在控制檯應用程序的Main方法中。原因是,如果你不阻止主線程,你的程序會過早退出。其次,如果您需要製作多個彼此不相互依賴的HTTP請求(即請求B不需要請求A的結果),那麼通過並行執行它們會帶來巨大的性能提升。更好的是,每個請求都不佔用線程,因爲這些調用是異步的,即它們在等待響應時不會阻塞線程,所以同一個線程可以有效地觸發許多併發請求。

我不會重新編寫代碼,但我會建議我怎麼會重組它:

static void Main(string[] args) 
{ 
    // start all async tasks in parallel. 
    var tasks = GetEvents().Select(GetEventDetailsAsync); 

    // wait for them all to complete. normally you should use await instead of Wait, 
    // but you can't because you're in the main method of a console app. 
    Task.WhenAll(task).Wait(); 
} 

static IEnumerable<Event> GetEvents() 
{ 
    // build a list of whatever metadata is needed to do your async work. 
    // do NOT do any actual async work here. 
} 

async static Task<EventDetailed> GetEventDetailsAsync(Event e) 
{ 
    // do all async work here, use await as needed, 
    // but only for one event (no loops). 
}