Blazor应用中Task.WhenAll并行调用API耗时未达预期原因排查
并行请求无加速的原因分析与解决方案
可能的原因
- 服务器端请求串行化
ASP.NET 体系中如果接口启用了Session,默认会对同一个Session的所有请求加排他锁,就算前端并行发起请求,后端也会串行处理,总耗时和串行调用基本一致。这是该类问题最常见的诱因。 - Blazor Server 电路串行调度
如果你的项目是Blazor Server而非Blazor WASM,Blazor的电路(Circuit)默认会对同一个用户会话的所有异步操作串行调度,避免线程安全问题,所以哪怕写了Task.WhenAll,请求也会挨个发起,总耗时和串行无差异。 - HttpClient 并发连接数限制
如果你手动配置了HttpClient的MaxConnectionsPerServer参数小于5,就会限制同域名的并发请求数,导致请求在客户端排队。 - 共享资源锁
检查SendRequest、_spinnerService这类全局服务的实现,是否存在lock语句或者其他同步等待逻辑,全局锁会直接把并行请求卡成串行。 - 浏览器同域名并发限制(概率极低)
现代浏览器对同域名的并发请求数默认是6~8,5个请求不会触发该限制,仅当同时发起更多请求时才会出现该问题。
排查与解决方案
- 优先验证服务器端性能:直接用Postman等工具并行调用5次该接口,若总耗时仍接近500ms,说明问题出在服务端。确认服务端是否启用了Session,可给对应接口加只读Session配置(ASP.NET Core可通过禁用该接口的Session锁实现,ASP.NET Framework可加
[SessionState(SessionStateBehavior.ReadOnly)]特性),允许并行处理。 - 检查HttpClient配置:确认没有手动设置过低的
MaxConnectionsPerServer,默认值为int.MaxValue,Blazor场景下无需修改,如果你主动改过改回默认即可。 - 排查代码锁逻辑:去掉
SendRequest、_spinnerService.Show()等公共方法中不必要的全局锁。 - Blazor Server场景适配:可以用
Task.Run包裹请求逻辑,强制在线程池上并行执行,注意做好业务变量的线程安全处理。 - 修正返回值接收逻辑:你当前的代码所有请求都给同一个
ModulesRoles变量赋值,最后只会保留最后一个请求的结果,建议改为用列表接收所有返回值:
var tasks = AllModules.Modules.Select(async moduleName => await WebAssemblyHttpService.Fetch<GetRolesByModuleNameResponse>("nemo", moduleName, HttpMethod.Post, "/api/admin/getmoduleroles"...)); var results = await Task.WhenAll(tasks); // 后续统一处理results数组完成业务赋值
内容的提问来源于stack exchange,提问作者RandomSlav
相关产品推荐
相关产品推荐

