【问题标题】:Throttle async tasks?限制异步任务?
【发布时间】:2016-05-03 14:20:01
【问题描述】:

我想知道如果要完成的任务数量很大,我们是否应该限制异步任务。假设您有 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 决定何时执行每个任务。但是,有人告诉我,实际上只有在任务是计算任务时才有效。当任务涉及网络请求时,第一种方法可能导致主机挂起???这是为什么呢?

【问题讨论】:

    标签: c# .net asynchronous async-await throttling


    【解决方案1】:

    在大多数情况下,您希望将自己限制在某些事情上。当您同时运行多个操作时,您总是会在某处保存一些状态。如果它们受 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;
    

    【讨论】:

    • 阅读这篇文章对我的并行编程来说是革命性的。德克萨斯人!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 2016-04-24
    • 1970-01-01
    • 2012-12-18
    相关资源
    最近更新 更多