【问题标题】:Will MediatR run the commands sequentially or in parallel?MediatR 会顺序还是并行运行命令?
【发布时间】:2019-11-20 05:45:55
【问题描述】:

我在应用程序中使用 MediatR 和 CQRS。以下两条语句存在于多个模块中,可能会在应用程序(它是一个 blazor 应用程序)中同时调用。

await Mediator.Send(new AddIdCommand { Id = id });

和

await Mediator.Send(new DeleteIdCommand { Id = id });

以下是更新同一文本文件的命令。

public class AddIdCommand : IRequest
{
    public int Id { get; set; }

    public class AddIdCommandHandler : IRequestHandler<DeleteIdCommand>
    {
        public async Task<Unit> Handle(AddIdCommand request, CancellationToken cancellationToken)
        {
            // .... update the text file with the Id deleted
        }
    }
}

public class DeleteIdCommand : IRequest
{
    public int Id { get; set; }

    public class DeleteIdCommandHandler : IRequestHandler<DeleteIdCommand>
    {
        public async Task<Unit> Handle(DeleteIdCommand request, CancellationToken cancellationToken)
        {
            // .... update the text file with the Id added
        }
    }
}

 ....
    protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();

两个命令中的Handle(...) 会一直按顺序调用吗? (因此无需担心多个进程更新同一个文件的问题。)

【问题讨论】:

  • 请注意 MediatR,但await 通常表示等待,除非当然下面有一些时髦的事情发生
  • 这是一个 blazor 应用程序。他们可能是多个用户同时使用该网站。此外,语句在地方被调用。

标签: c# cqrs mediator mediatr


【解决方案1】:

好吧,仅从这两行的上下文来看:

await Mediator.Send(new AddIdCommand { Id = id });
await Mediator.Send(new DeleteIdCommand { Id = id });

它将按顺序运行。

您可以在此处查看代码:

https://github.com/jbogard/MediatR/blob/master/src/MediatR/Mediator.cs

var requestType = request.GetType();

var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
    t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));

return handler.Handle(request, cancellationToken, _serviceFactory);

它只是返回异步处理方法的任务。 因此,如果您等待后续的句柄方法,它会同步运行(相对于彼此)。

但是你以

结束你的问题

因此无需担心多个进程更新同一个文件 问题。

我不确定。即使您正在等待两个发送方法,如果有两个独立的进程调用这两个方法,并且它们都针对同一个文件,它们之间的顺序将无法保证。 Mediator.cs 对多线程应用程序所做的唯一同步是 _requestHandlers 是一个 ConcurrentDictionary。

因此它保证了这一行永远不会为同一类型初始化多个处理程序,即使在并行调用时也是如此:

var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
        t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));

Handle 调用不同步。

【讨论】:

  • 其实在调用你的handle方法之前,如果先经过RequestHandlerWrapper,但是你可以看一下它的实现,看起来并没有同步。
  • “不保证他们之间的顺序”没关系。看来我需要使用 lock {} 或有一个队列来同步执行。
  • 事件呢?同一事件的多个事件处理程序是否也按顺序运行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 2014-10-05
  • 1970-01-01
相关资源
最近更新 更多