如何实现异步观察者模式或事件?

3
我正在寻找一种实现以下功能的方法:
A说:“嘿, X 发生了。再见。”
其他人看到这个消息后开始做一些工作。
换句话说,我想要触发一个事件,让其他人以“fire and forget”的方式处理它。
因此,我研究了观察者模式:https://msdn.microsoft.com/en-us/library/dd783449(v=vs.110).aspx。然而,这个例子是同步的,如果观察者需要很长时间才能完成工作,则通知方法会被阻塞很长时间。
我还查看了如何引发事件:https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx。同样,这个例子也是同步的,当处理程序需要很长时间来处理事件时,发送者会被阻塞很长时间。
我的问题是: 如何在 C# 中实现 fire and forget 的事件 / 消息 / 委托?

1
看一下事件总线的一些实现。 - tym32167
1
可能是如何使事件处理程序异步运行?的重复。 - Tatranskymedved
@Tatranskymedved 但是这个副本已经过时了,它是一个完全过时的解决方案... - Matías Fidemraizer
1个回答

3

也许你应该了解一下任务并行库(TPL)数据流。其中有一个叫做ActionBlock<TInput>的数据流可能是一个很好的起点:

ActionBlock<TInput>类是一个目标块,当它接收到数据时调用一个委托。可以将ActionBlock<TInput>对象看作在数据可用时异步运行的委托。提供给ActionBlock<TInput>对象的委托可以是Action类型或者类型为System.Func<TInput, Task>[...]

因此,将Func<TInput, Task>提供给ActionBlock<TInput>来执行异步操作怎么样?我修改了在TPL Dataflow MSDN article中找到的示例:
List<Func<int, Task>> observers = new List<Func<int, Task>>
{
      n => Console.WriteLine(n),
      n => Console.WriteLine(n * i),
      n => Console.WriteLine(n * n / i)
};

// Create an ActionBlock<int> object that prints values
// to the console.
var actionBlock = new ActionBlock<int>
(
    n => 
    {
         // Fire and forget call to all observers
         foreach(Func<int, Task> observer in observers)
         {
              // Don't await for its completion
              observer(n);
         }         
    }
);

// Post several messages to the block.
for (int i = 0; i < 3; i++)
{
   actionBlock.Post(i * 10);
}

// Set the block to the completed state
actionBlock.Complete();

// See how I commented out the following sentence.
// You don't wait actions to complete as you want the fire
// and forget behavior!
// actionBlock.Completion.Wait();

你可能还想看看BufferBlock<T>

@tym32167 这是 Task Parallel Library 的一部分。它可以在多个 CPU 核心上真正地并行处理工作。 - Matías Fidemraizer
@tym32167 请查看此文章 https://msdn.microsoft.com/zh-cn/library/mt604413(v=vs.111).aspx - Matías Fidemraizer
@tym32167,我不会太担心线程的生成。看看像NodeJS或Redis这样经过验证的技术,它们是单线程的,可以以光速交付工作。使用Dataflows,您甚至拥有了更强大的工具,因为它可以生成物理线程,并且根据情况,它可能会胜过逻辑线程。 - Matías Fidemraizer
@tym32167 没问题! - Matías Fidemraizer
@user369117,请查看我的编辑答案,我已经添加了一个观察者列表。 - Matías Fidemraizer
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接