2016-01-13 101 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). 
}