【发布时间】:2019-05-30 20:33:38
【问题描述】:
当我执行代码时,在WhenAll 之后检查idList 是空的,如果我在WhenAll 之后使用断点单步执行它,一切都会按预期工作。
此代码在非异步方法中。
就好像让它自己运行并不是启动任务。
var currentPage = 1;
List<Result> idList = new List<Result>();
var response = this.GetDocuments(currentPage).Result;
//idList.AddRange(response.results);
var tasks = new List<Task>();
for (var i = 0; i < response.meta.page.total_pages; ++i)
{
var t = new Task(() =>
{
response = this.GetDocuments(i+1).Result;
idList.AddRange(response.results);
});
tasks.Add(t);
t.Start();
}
Task.WhenAll(tasks).Wait();
public async Task<ResponseObject> GetDocuments(int currentPage)
{
var result = await httpClient.GetAsync($"api/as/v1/engines/urlname/documents/list?page[current]={currentPage}").ConfigureAwait(false);
if (!result.IsSuccessStatusCode)
{
loggly.Error($"Exception: ScheduledJobBase, IndexPages, failed when getting documents from Swiftype, response: { result }");
return null;
}
return await result.Content.ReadAsAsync<ResponseObject>().ConfigureAwait(false); ;
}
【问题讨论】:
-
表达式
Task.WhenAll(tasks).ConfigureAwait(false)返回一个Task,你需要await它(或者在非异步方法中调用.Wait())。 -
您还将循环变量 (
i) 传递到创建闭包的任务的 lambda 中,因此您的GetDocuments调用 可能 对 @987654333 使用错误的值@。为了解决这个问题,您可以在创建任务之前创建一个中间变量。喜欢var i1 = i; ... GetDocuments(i1+1) ... -
你可以从这个answer开始
-
还有一点——正如@Hakit01 提到的,从多个线程访问非并发集合可能会导致很多讨厌的错误。因此,您可以使用并发集合(
System.Collections.Concurrent命名空间),或者在您的情况下,我会完全避免使用集合。Task.WhenAll创建一个任务,返回底层任务的所有结果,因此从任务中返回一个值,然后将它们聚合到一个集合中可以解决问题。此外,您无需手动创建任务 - 只需从您放入任务构造函数的 lambda 中提取一个异步方法即可。
标签: c# .net asynchronous task