我想知道如果要完成的任务数量很大,我们是否应该限制异步任务。假设您有1000个URL,您是否一次触发所有请求并等待所有请求:
var tasks = urlList.Select(url => downloadAsync(url));
await Task.WhenAll(tasks);
或者您批量处理请求并逐个处理:
foreach (var urlBatch in urlList.BatchEnumerable(BatchSize)){
var tasks = urlBatch.Select(url => downloadAsync(url));
await Task.WhenAll(tasks);
}
我认为批处理不是必需的,因为第一种方法(一次触发所有请求)将创建ThreadPool
计划的任务,因此我们应该让ThreadPool
决定何时执行每项任务。但是,有人告诉我,实际上只有在任务是计算任务时才有效。当任务涉及网络请求时,第一种方法可能导致主机挂起???那是为什么?
答案 0 :(得分:7)
在大多数情况下,你想限制自己。当您同时运行多个操作时,总是会将某个状态保留在某个位置。如果它们是CPU绑定的,则任务存储在等待线程的ThreadPool
队列中,如果它是异步的,那么您将状态机放在堆上。
即使异步操作通常会占用一些有限的资源,无论是带宽,端口,远程数据库服务器的CPU等。
您不必一次限制一个批次(因为您需要等待上一次操作完成而不是启动其他操作)。您可以使用SlimSemahpore
甚至更好的TPL数据流块进行限制:
var block = new ActionBlock<string>(
url => downloadAsync(url),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 });
urlList.ForEach(url => block.Post(url));
block.Complete();
await block.Completion;