2015-04-06 39 views
-1

有这question提到使用async/await来防止死锁。 在我的情况下,这个代码只适用于下面显示的elementsInList变量中的2或3个元素。 我想知道是否有一个数量因素可能会影响提高或不僵局。C#AsParallel在调用HttpClient时被阻止

我尝试使用下面的代码块:

var responses = elementsInList.AsParallel() 
        .WithDegreeOfParallelism(elementsInList.Count) 
        .Select(elementInList => GetResponse(elementInList, timeout)).ToList(); 

(...)

public JObject GetResponse(JObject request, TimeSpan timeout) 
     { 
       var endpoint = ConfigurationManager.AppSettings.Get("MyEndPoint"); 

       try 
       { 
        using (var client = new HttpClient()) 
        { 
         client.DefaultRequestHeaders.Accept.Clear(); 
         client.Timeout = timeout; 

         IList<MediaTypeFormatter> formatters = GetMediaTypeFormatters(); 
         HttpResponseMessage response = client.PostAsJsonAsync(EndPoint, request).Result; 

         if (response.IsSuccessStatusCode) 
         { 
          return response.Content.ReadAsAsync<T>(formatters).Result; 
         } 

         throw new Exception(response.ReasonPhrase); 
        } 

       } 
       catch (Exception ex) 
       { 
        return new JObject() 
        { 
         new JProperty("Exception", "Invalid response. " + ex.Message) 
        }; 
       } 
     } 

如果我调试代码,当.AsParallel线被击中,代码被阻止,它永远不会返回答案或进入下一行。 这似乎正在发生一场僵局。

我想添加一个细节,如果我使用2或3个元素的代码,它可以正常工作,但是,当调用像30-50个元素时,它会失败。是否有数量因素可能会导致第二种情况下的僵局,而不是第一种?我很好奇,如果它影响与否,或者它也可能只有2或3个元素生成。

+0

'。结果'基本上'.Wait' - 确保阅读链接的副本,并在必要时更新问题/评论以重新打开。 –

+0

你是对的,谢谢你的链接到其他类似的情况。在我的情况下,代码显示了一些元素的作品。是否有数量因素可能会导致/产生僵局?或者甚至有两个因素会导致僵局?不知道为什么这个代码适用于很少的元素。 –

+1

只要ASP.Net/WinForms同步上下文中的线程运行调用Wait/Result,它就应该死锁。我不确定'.AsParallel'如何并行运行单独的操作,但我认为有些会在当前的UI线程上运行并导致死锁。挂起时检查callstack可以揭示问题的确切来源。 –

回答

2

作为一般的经验法则,如果您的应用程序需要执行CPU密集型工作,则只能使用并行技术。对于I/O绑定的工作,请使用异步技术。对于极其罕见的您需要同时和异步代码的情况,请考虑像TPL Dataflow这样的技术。

在你的情况,有没有做CPU密集型的工作,所以删除所有平行的东西,只是用async/await代替:

public async Task<JObject> GetResponseAsync(JObject request, TimeSpan timeout) 
{ 
    var endpoint = ConfigurationManager.AppSettings.Get("MyEndPoint"); 
    try 
    { 
    using (var client = new HttpClient()) 
    { 
     client.DefaultRequestHeaders.Accept.Clear(); 
     client.Timeout = timeout; 

     IList<MediaTypeFormatter> formatters = GetMediaTypeFormatters(); 
     HttpResponseMessage response = await client.PostAsJsonAsync(EndPoint, request); 

     if (response.IsSuccessStatusCode) 
     return await response.Content.ReadAsAsync<T>(formatters); 

     throw new Exception(response.ReasonPhrase); 
    } 
    } 
    catch (Exception ex) 
    { 
    return new JObject() 
    { 
     new JProperty("Exception", "Invalid response. " + ex.Message) 
    }; 
    } 
} 

用法:

var responses = await Task.WhenAll(
    elementsInList.Select(x => GetResponseAsync(x, timeout))); 
+0

非常感谢您的回答。这是否意味着当我们使用HttpClient ReadAsAsync和多个线程/任务时,我们需要以强制方式使用异步/等待?或者可能有没有发生死锁的情况? –

+0

@AlbertoMontellano:如果你使用'HttpClient',你应该使用'await'。线程/任务的数量与它无关。是的,有些情况下不会出现死锁,但您不应该依赖它们。 –

+0

感谢您的指导和澄清。 –