节流异步任务?
Throttle async tasks?
我想知道如果要完成的任务数量很大,我们是否应该限制异步任务。假设您有 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
决定何时执行每个任务。但是,有人告诉我,实际上只有当任务是计算任务时才有效。当任务涉及网络请求时,第一种方法可能导致主机挂起 ???这是为什么?
在大多数情况下,您想限制自己做某事。当您同时进行多个操作 运行 时,您总是会在某处保存一些状态。如果它们是 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;
我想知道如果要完成的任务数量很大,我们是否应该限制异步任务。假设您有 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
决定何时执行每个任务。但是,有人告诉我,实际上只有当任务是计算任务时才有效。当任务涉及网络请求时,第一种方法可能导致主机挂起 ???这是为什么?
在大多数情况下,您想限制自己做某事。当您同时进行多个操作 运行 时,您总是会在某处保存一些状态。如果它们是 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;