【问题标题】:Async code deadlocking even after using ConfigureAwait(false)即使在使用 ConfigureAwait(false) 之后,异步代码也会死锁
【发布时间】:2015-08-08 06:06:59
【问题描述】:

如果我使用 Http Async 而不是 Sync 之一,我正在尝试测量时间的改进,但是由于我搜索并发现可以使用 ConfigureAwait(false) 来解决这种情况,但是由于 Async 方法上下文,下面的代码死锁了代码仍然死锁。有关如何解决此问题的任何建议?

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        var entities = new List<string>() { "iron+man+3", "dark+knight+rises", "frozen+movie" };
        stopwatch.Start();
        int taskStatus = AsyncGet(entities).Result;
        stopwatch.Stop();
        Console.WriteLine(stopwatch.ElapsedTicks);
        stopwatch.Reset();
        stopwatch.Start();
        SyncGet(entities);
        stopwatch.Stop();
        Console.WriteLine(stopwatch.ElapsedTicks);
        var depTime = DateTime.UtcNow;
        depTime = depTime.AddMilliseconds(-depTime.Millisecond);
        Console.WriteLine(depTime.ToString("yyyy-MM-ddTHH:mm:ss.fff"));
        Console.Read();
    }

    private static async Task<int> AsyncGet(List<string> entities)
    {
        var taskHttpList = new List<Task<WebResponse>>();
        var taskStreamList = new List<Task<string>>();
        var uriTemplate = "https://www.google.co.in/?#q={0}";
        foreach (var entity in entities)
        {
            Uri uri = new Uri(string.Format(uriTemplate, entity));
            var request = WebRequest.Create(uri);
            taskHttpList.Add(request.GetResponseAsync());
        }
        foreach (var task1 in taskHttpList)
        {
            var response = (HttpWebResponse)await task1.ConfigureAwait(false);
            taskStreamList.Add((new StreamReader(response.GetResponseStream())).ReadToEndAsync());
        }
        foreach (var task in taskStreamList)
        {
            var responseStr = (String)await task.ConfigureAwait(false);
        }
        return 0;
    }

    private static void SyncGet(List<string> entities)
    {
        var uriTemplate = "https://www.google.co.in/?#q={0}";
        foreach (var entity in entities)
        {
            Uri uri = new Uri(string.Format(uriTemplate, entity));
            var request = WebRequest.Create(uri);
            var response = request.GetResponse();
            var str = new StreamReader(response.GetResponseStream()).ReadToEnd();
        }
    }
}

【问题讨论】:

  • 您是否尝试过实现类似于 SyncGet 的 AsyncGet,即一个内部有两个“等待”的 foreach 循环?
  • 是的,这行得通,但是 HTTP 异步的整个想法就丢失了。我只是想了解是否启动一堆 HTTP 异步请求,然后在所有请求开始后等待它们,我是否会在所花费的时间方面获得任何性能改进。
  • 你没有处理任何东西。这可能会导致连接池耗尽导致阻塞。处置所有资源。
  • @user1017860: 1) 异步并不比同步快;这不是 async 的意义所在。 2)在不理解它们的情况下应用ConfigureAwait(false)之类的“解决方案”只会使代码复杂化,而不是纠正它。
  • @Stephen 据我了解,当您有大量网络绑定或 I/O 绑定请求时,异步很有用。在这个特定的场景中,我有很多 WebRequest。你能解释一下为什么 Async 不适合这里吗?我是异步编程的新手,所以不太清楚它在实际意义上的用处。您能否也举一个控制台应用程序类型场景的示例,其中异步很有用。

标签: c# asynchronous


【解决方案1】:

我想处理 IO 完成事件的线程数是有限制的。与其以同步方式处理它,不如为每个工作项构建一个完整的任务链:

 private static async Task<int> AsyncGet(List<string> entities)
 {
     var tasks = new List<Task<string>>();

      foreach (var entity in entities)
      {
        var t =  AsyncGetResponse(entity);
        tasks.Add(t); 
      }

      await Task.WaitAll(tasks.ToArray()).ConfigureAwait(false);
      return 0
  }

 static async Task<string> AsyncGetResponse(string entity)
 {
        const string uriTemplate = "https://www.google.co.in/?#q={0}";
        Uri uri = new Uri(string.Format(uriTemplate, entity));
        var request  = WebRequest.Create(uri);
        string result;

        using (var response = (HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false))
        {
            var reader = new StreamReader(response.GetResponseStream()))
            result = await (string) reader.ReadToEndAsync().ConfigureAwait(false);
        }

        return result; 

 }

正如 cmets 中提到的,不要忘记释放分配的资源,例如 WebResponse。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    相关资源
    最近更新 更多