user1017860
user1017860

Reputation: 320

Async code deadlocking even after using ConfigureAwait(false)

I am trying to measure improvement in amount of time if I use Http Async instead of Sync one, but the code below deadlocks because of Async method contexts I searched and found one can use ConfigureAwait(false) to fix the situation but the code still deadlocks. Any suggestions on how I can fix this?

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();
        }
    }
}

Upvotes: 2

Views: 961

Answers (1)

alexm
alexm

Reputation: 6882

I imagine that there is a limit on the number of threads handling IO completion events. Instead of processing it in the lockstep fashion build a complete chain of tasks per work item:

 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; 

 }

As was mentioned in comments, don't forget to dispose allocated resources, such as WebResponse.

Upvotes: 2

Related Questions