Task.WaitAll无限期阻塞

时间:2014-10-19 07:57:05

标签: c# async-await

我有以下课程:

class MultiWebProgram
{
  static void Main(string[] args)
  {
    string[] websites = new string[]
    {
       "https://www.google.com/search?q=one",
       "https://www.google.com/search?q=two",
       "https://www.google.com/search?q=three",
       "https://www.google.com/search?q=four"
    };

    Task<int>[] taskList = new Task<int>[websites.Length];
    int i = 0;
    foreach(var website in websites)
    {
      taskList[i] = Task<int>.Run(() => GetSiteBytes(website));
      i++;
    }
    Task.WaitAll(taskList);
  }

  public static int GetSiteBytes(string website)
  {
    WebClient client = new WebClient();
    var stream = client.OpenRead(new Uri(website));
    byte[] buffer = new byte[4096];
    int totalBytes = 0;
    int bytesRead = 0;
    do
    {
      bytesRead = stream.Read(buffer, 0, 4096);
      totalBytes += bytesRead;
    }
    while (bytesRead >= 4096);
    Console.WriteLine("Got {0} bytes from {1}", totalBytes, website);
    return totalBytes;
  }
}

当我运行它时,代码会阻塞WaitAll命令。

我尝试将程序更改为:

class MultiWebProgram
{
  static void Main(string[] args)
  {
    string[] websites = new string[]
    {
       "https://www.google.com/search?q=one",
       "https://www.google.com/search?q=two",
       "https://www.google.com/search?q=three",
       "https://www.google.com/search?q=four"
    };

    Task<int>[] taskList = new Task<int>[websites.Length];
    int i = 0;
    foreach(var website in websites)
    {
      taskList[i] = GetSiteBytesAsync(website);
      i++;
    }
    Task.WaitAll(taskList);
  }

  public async static Task<int> GetSiteBytesAsync(string website)
  {
    WebClient client = new WebClient();
    var stream = await client.OpenReadTaskAsync(new Uri(website));
    byte[] buffer = new byte[4096];
    int totalBytes = 0;
    int bytesRead = 0;
    do
    {
      bytesRead = await stream.ReadAsync(buffer, 0, 4096);
      totalBytes += bytesRead;
    }
    while (bytesRead >= 4096);

    Console.WriteLine("Got {0} bytes from {1}", totalBytes, website);
    return totalBytes;
  }
}

换句话说,我将GetSiteBytes方法设为异步 - 但没有区别。

我注意到了一件事;当我启动Fiddler并运行任一版本的程序时,没有阻止。

这可能会发生什么?

**编辑:** 问题似乎是OpenRead方法。当我使用DownloadData / DownloadDataAsync时,阻塞消失了。

1 个答案:

答案 0 :(得分:1)

您忘记了在读取所有数据后关闭流。试试这个,它会起作用:

using (var stream = client.OpenRead(new Uri(website)))
{
...
}

我不确定 OpenRead 方法是做什么的,但我认为它分配了一些有限的资源,你不能使用超过可用的资源。我个人总是假设如果一个方法返回一个流,那么我必须关闭它。