发布
.NET 6(在2021年11月),对于除了 ASP.NET 之外的所有应用程序而言,限制并发异步 I/O 操作数量的推荐方法是使用
Parallel.ForEachAsync
API,并配置
MaxDegreeOfParallelism
。以下是实际使用示例:
string[] urls = { "http://google.com", "http://yahoo.com", };
var client = new HttpClient();
var options = new ParallelOptions() { MaxDegreeOfParallelism = 20 };
await Parallel.ForEachAsync(urls, options, async (url, cancellationToken) =>
{
var html = await client.GetStringAsync(url, cancellationToken);
});
在上面的示例中,
Parallel.ForEachAsync
任务以异步方式进行等待。如果需要,您还可以同步地
Wait
它,这将阻塞当前线程直到所有异步操作完成。同步的
Wait
的优点是,在出现错误时,所有异常都会传播。相反,
await
运算符只按设计传播第一个异常。如果这是一个问题,您可以在
这里找到解决方案。
关于ASP.NET的注意事项:Parallel.ForEachAsync API通过在线程池上启动多个工作器(任务),并且所有工作器都以并行方式调用body委托来工作。这与MSDN文章“异步编程:介绍ASP.NET上的异步/等待”中提供的建议相悖:
“您可以通过等待Task.Run来启动一些后台工作,但这样做没有意义。实际上,这将通过干扰ASP.NET线程池的启发式算法来损害可伸缩性。如果您在ASP.NET上有需要进行CPU绑定工作,最好直接在请求线程上执行。作为一般规则,在ASP.NET上不要将工作排队到线程池。”
因此,在ASP.NET应用程序中使用Parallel.ForEachAsync可能会损害应用程序的可伸缩性。在ASP.NET应用程序中,并发是可以接受的,但应避免并行处理。
从目前提交的答案中,只有
Dogu Arslan's的答案适用于ASP.NET应用程序,尽管在异常情况下它的行为并不理想(即在错误发生时,
Task
可能无法足够快地完成)。
HttpClient
实现了IDisposable
接口,需要对其进行释放,尤其是当你要使用1000个以上的实例时。可以将HttpClient
用作多个请求的单例。 - Shimmy WeitzhandlerHttpClient
:https://dev59.com/WGUo5IYBdhLWcg3w3ymi#15708633 - avs099