调用HttpClient时,C#AsParallel被阻止

时间:2015-04-06 21:49:40

标签: c# multithreading thread-safety dotnet-httpclient

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

我正在尝试使用以下代码块:

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个元素生成。

1 个答案:

答案 0 :(得分: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)));