RanToCompletion仍然在等待时
我需要编写一个方法,可以异步加载和解析多个网站。 这是我的方法的简化代码。RanToCompletion仍然在等待时
using (HTMLParser parser = new HTMLParser(proxy))
{
var tasks = totalSites.Select(s =>
{
return new Task(async() =>
{
s.Entity = await parser.GetSiteDataAsync(s.Entity).ConfigureAwait(false);
});
}).ToArray();
foreach (var task in tasks)
task.Start();
await Task.WhenAll(tasks).ConfigureAwait(false);
}
HTMLParser
类使用HttpClient
加载网站并配置它脱手。完整的代码也使用CancellationToken
来取消,并使用SemaphoreSlim
来降低并行度。
问题是,当任务开始等待分析数据时,它的状态设置为RanToCompletion
。然后程序通过Task.WhenAll
并配置HTMLParser
导致OperationCanceledException
在HttpClient
中。
就像我在评论中所说的,你不应该明确地创建Task
s。我想你需要的是沿着线的东西:
using (HTMLParser parser = new HTMLParser(proxy))
{
var tasks = totalSites.Select(s => populateEntity(s)).ToArray();
/* returned tasks are already hot */
//foreach (var task in tasks)
// task.Start();
await Task.WhenAll(tasks).ConfigureAwait(false);
}
,然后分别:
public async Task<WhateverSIs> populateEntity(WhateverSIs s)
{
s.Entity = await parser.GetSiteDataAsync(s.Entity).ConfigureAwait(false);
return s;
}
我们没有创建任何Tasks
明确 - 我们只是async
方法,包括使用那些暴露GetSiteDataAsync
。
谢谢!我自己也做了同样的事情。昨天我尝试了这种方法,但是我写了lambda中的所有逻辑,并且取消不起作用,并迫使我明确地创建任务。 –
@AndreyAlonzov - 异步lambdas的问题是他们可以很容易地生成'Func'或'Action'委托 - 而'Action'有效'async void'。如果你看看[你通过lambda的地方](https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.task(v = vs.110).aspx)你会发现它只能采用一个“Action” - 所以你无法跟踪你的lambda的进度。 –
如果你的代码将被I/O绑定,你的方法通常不应该明确地创建新的Task对象。我认为你现在的代码最后是'Task's包装其他'Task's,这不是盛大的。 –
@GWigWam,对不起,我错过了简化我的代码。 's'用于创建'vm'。 @Damien_The_Unbeliever我认为你是对的:我需要创建多个任务来加载它并行的多个网站。 –
@AndreyAlonzov - 但是对于I/O绑定的工作,你*不应该创建任务 - 你应该利用'async'和'await',但是唯一的你应该处理的任务是通过'async'方法返回的*。 –