MediatR的Publish默认同步顺序执行,逐个await handler;ParallelNoWait策略真正并发但不等待、吞异常;SyncContinueOnException仍同步但异常不中断后续;可控并发需手动Task.WhenAll+错误处理。

MediatR 的 Publish 默认是同步顺序执行,不是并发
很多人看到 IPublisher.Publish 返回 Task 就默认它天然支持并发,其实不然。MediatR 的默认行为是:所有 IAsyncNotificationHandler 按注册顺序**逐个 await**,一个 handler 抛异常会中断后续 handler 执行(除非显式配置异常处理策略)。这和你手动写 await handler1.Handle(...); await handler2.Handle(...); 效果一致。
ParallelNoWait 策略:真正并发但完全放弃等待与错误传播
这是 MediatR 8+ 引入的并发策略,通过 ServiceCollection 配置启用:
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.NotificationPublisher = new ParallelNoWaitPublisher(); // 关键
});
它会把所有 handler 包装进 Task.Run 并发启动,然后立即返回已完成的 Task.CompletedTask —— 也就是说:
-
Publish调用后几乎立刻返回,不等任何 handler 完成 - handler 内部抛出的异常会被吞掉(仅记录到
ILogger),不会向上冒泡 - 无法感知 handler 是否成功、耗时多久、是否被取消
- 不适合依赖 handler 副作用(如发消息、更新缓存)后继续逻辑的场景
SyncContinueOnException 是假“并发”,本质是同步兜底
这个策略名字有误导性:它**不并发**,也不并行。它的作用只是让某个 handler 抛异常时,不影响其他 handler 继续执行 —— 仍按注册顺序同步调用,只是把每个 Handle 包在 try/catch 里:
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.NotificationPublisher = new SyncContinueOnExceptionPublisher();
});
典型适用场景:
- 多个日志/埋点 handler,一个失败不该阻塞另一个
- 监控类通知(如发送指标),允许部分失败
- 你明确不需要 await 结果,但又希望保留调用顺序和可调试性
注意:它仍会等待全部 handler 同步执行完才返回 Task,只是异常不中断流程。
自己实现可控并发:用 Task.WhenAll + 显式错误处理
如果既要并发,又要捕获结果或控制失败策略,MediatR 不提供开箱即用方案,得自己封装。常见做法是在业务层手动聚合 handler 调用:
var tasks = handlers.Select(h => h.Handle(notification, cancellationToken));
var results = await Task.WhenAll(tasks); // 等全部完成,任一失败则整体失败
// 或带错误隔离:
var results = await Task.WhenAll(
handlers.Select(h =>
Task.Run(() => h.Handle(notification, cancellationToken))
.ContinueWith(t => t.Exception?.InnerException, TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith(t => t.Result ?? null)
)
);
关键点:
- 必须从 DI 容器解析
IEnumerable,不能靠 MediatR 自动分发> -
Task.WhenAll失败时抛第一个异常;若要忽略部分失败,需用ContinueWith或await task.OrNothing()类辅助方法 - 并发数不受控时可能压垮下游(如 DB 连接池),建议配合
SemaphoreSlim限流
MediatR 的 Publish 并发能力很轻量,真正需要可靠异步协作时,往往该考虑事件总线(如 MassTransit)或后台任务队列(如 Hangfire)了。










