【问题标题】:Task.WaitAll gets stuckTask.WaitAll 卡住了
【发布时间】:2016-02-16 20:00:16
【问题描述】:

我有一段代码如下所示:

    var taskList = new Task<string>[masterResult.D.Count];
    for (int i = 0; i < masterResult.D.Count; i++)        //Go through all the lists we need to pull (based on master list) and create a task-list
    {
        using (var client = new WebClient())
        {
            Task<string> getDownloadsTask = client.DownloadStringTaskAsync(new Uri(agilityApiUrl + masterResult.D[i].ReferenceIdOfCollection + "?$format=json"));
            taskList[i] = getDownloadsTask;
        }
    }

    Task.WaitAll(taskList.Cast<Task>().ToArray());      //Wait for all results to come back

代码在 Task.WaitAll 之后冻结...我知道为什么,这是因为客户端在调用时已经被处理,是否可以将其处理延迟到以后?你能推荐另一种方法吗?

【问题讨论】:

  • 好吧,测试假设:当using 围绕其他所有东西移动时会发生什么?这是确认还是拒绝“想法”?
  • 它是否在异步函数中运行?它是否一直“向上”异步?
  • 外码是什么?重要的是它在调用堆栈中一直是异步的。
  • 不,函数是同步的
  • 外部方法可能是不相关的(绝对不是异步的),因为调用了Task.WaitAll

标签: c# task-parallel-library


【解决方案1】:

您需要在任务中创建和处置 WebClient。我没有办法对此进行测试,但看看是否指向正确的方向:

    var taskList = new Task<string>[masterResult.D.Count];
    for (int i = 0; i < masterResult.D.Count; i++)        //Go through all the lists we need to pull (based on master list) and create a task-list
    {
        taskList[i] = Task.Run(() =>
        {
            using (var client = new WebClient())
            {
                return client.DownloadStringTaskAsync(new Uri(agilityApiUrl + masterResult.D[i].ReferenceIdOfCollection + "?$format=json"));

            }
        });
    }

    Task.WaitAll(taskList.Cast<Task>().ToArray());  

【讨论】:

  • 我得到了这个方法,除非你需要将循环索引重新分配给一个新变量,否则你会得到一个 OutOfRange 异常。更多信息:stackoverflow.com/questions/2741870/…
  • 是的,当我做这样的事情时,我只是使用了List&lt;Task&gt;,然后使用了.ToArray()。循环索引会出现一些问题也就不足为奇了。
【解决方案2】:

我看不出该代码将如何工作,因为您在任务运行之前处置了WebClient

你想做这样的事情:

var taskList = new Task<string>[masterResult.D.Count];
for (int i = 0; i < masterResult.D.Count; i++)        //Go through all the lists we need to pull (based on master list) and create a task-list
{
    var client = new WebClient();
    Task<string> task = client.DownloadStringTaskAsync(new Uri(agilityApiUrl + masterResult.D[i].ReferenceIdOfCollection + "?$format=json"));
    task.ContinueWith(x => client.Dispose());
    taskList[i] = task;
}

Task.WaitAll(taskList.Cast<Task>().ToArray());      //Wait for all results to come back

即如果您在第一个循环中处理WebClient,则在使用Task.WaitAll 触发任务时不会分配它。任务完成后将调用ContinueWith 调用,因此可用于处置每个WebClient 实例。

但是,要获取对单个主机执行并发请求的代码,您需要配置服务点。阅读这个问题:Trying to run multiple HTTP requests in parallel, but being limited by Windows (registry)

【讨论】:

  • 它没有,完全运行,这是正确的,它在尝试时冻结。
  • 不是我,但我会尝试你的解决方案,如果可行的话 +1
  • -1 用于冒充答案的评论,但即使是现在,这也不是问题,而且这不是您建议中的好代码。 WebClient 可以而且应该重复用于多个请求。
  • @weston,webclient不支持并发请求,我已经想到了这个办法
  • 也许您可以在 Task.ContinueWith 上处置客户,而不是持有单独的列表,对吧?
猜你喜欢
  • 2012-06-23
  • 2021-10-08
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多