【问题标题】:Starting tasks in a for loop and then doing waitall on all of them在 for 循环中启动任务,然后对所有任务执行 waitall
【发布时间】:2014-03-14 02:03:47
【问题描述】:

我看到了几篇关于此的帖子...但大多数人是手动创建任务而不是从 API 接收它。

我有这个代码

        Task[] tasks = new Task[companyCount];
        // start all threads
        for(int i = 0; i < companyCount; i++) {
            string input = GetNextCompanyRecord(i);
            string token = GetUserToken();
            HttpClient client = GetHttpClient();
            StringContent content = CreateStringContent(input);
            var x = client.PostAsync(companyUrlString, content).ConfigureAwait(continueOnCapturedContext: false);
            tasks[i] = x;
        }
        Task.WaitAll(tasks);

目标是我在 for 循环中为每条记录启动任务,然后在所有任务启动时...执行单个 waitall。

问题是我无法将 x 变量分配给任务数组。

PostAsync 方法没有向我返回任务。相反,它返回 ConfiguredTaskAwaitable。但我希望我能得到 Task 并且能够将它添加到我的数组中,然后等待。

【问题讨论】:

  • 去掉不必要的.ConfigureAwait(continueOnCapturedContext: false),你就是金子了。

标签: c# task-parallel-library


【解决方案1】:

就这样吧:

Task<HttpResponseMessage>[] tasks = new Task<HttpResponseMessage>[companyCount];
for(int i = 0; i < companyCount; i++)
{
    string input = GetNextCompanyRecord(i);
    string token = GetUserToken();
    HttpClient client = GetHttpClient();
    StringContent content = CreateStringContent(input);
    var x = client.PostAsync(companyUrlString, content);
    tasks[i] = x;
}
Task.WaitAll(tasks);

但是,也许更清洁的方法是这样做:

var tasks =
    from i in Enumerable.Range(0, companyCount)
    let input = GetNextCompanyRecord(i)
    let token = GetUserToken()
    let client = GetHttpClient()
    let content = CreateStringContent(input)
    select client.PostAsync(companyUrlString, content);

Task.WaitAll(tasks.ToArray());

甚至更好:

using (var client = GetHttpClient())
{
    var tasks =
        from i in Enumerable.Range(0, companyCount)
        let input = GetNextCompanyRecord(i)
        let token = GetUserToken()
        let content = CreateStringContent(input)
        select client.PostAsync(companyUrlString, content);

    Task.WaitAll(tasks.ToArray());
}

【讨论】:

  • WaitAll 完成后,现在如何从每个任务中获取所有 HttpResponseMessage?
  • @KnowsNotMuch - 在执行WaitAll 之前,将任务分配给一个数组,然后在该数组上等待。然后您可以使用相同的数组来检索所有响应消息。只需从每个任务中获取Value。这里重要的是您必须使用相同的任务数组。如果您尝试改用 tasks 查询,您将创建一组新任务。
【解决方案2】:

PostAsync 返回一个Task(准确地说是一个Task&lt;HttpResponseMessage&gt;),但是你在它上面调用ConfigureAwait,它返回一个ConfiguredTaskAwaitable

尝试先获取对任务的引用,然后调用ConfigureAwait

var task = client.PostAsync(companyUrlString, content);
ConfiguredTaskAwaitable awaitable = task.ConfigureAwait(continueOnCapturedContext: false);
tasks[i] = task;

另外,请考虑:

  • 删除对 ConfigureAwait 的调用,因为您似乎不需要它。
  • 如果您想在任务完成后检索任务结果,请将您的数组从 Task[] 更改为 Task&lt;HttpResponseMessage&gt;[]

【讨论】:

  • 虽然缺乏解释,但Enigmativity的回答要好得多,你应该接受他的代替。
  • 好的。谢谢。我首先看到了您的答案,因此将其标记为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 2014-09-27
  • 1970-01-01
相关资源
最近更新 更多