繁体   English   中英

事件与收益率

[英]Events vs. Yield

我有一个多线程应用程序,它为几个硬件工具生成线程。 每个线程基本上都是一个无限循环(在应用程序的生命周期内),它会轮询硬件以获取新数据,并在每次收集新内容时激活一个事件(传递数据)。 有一个侦听器类可以合并所有这些乐器,执行一些计算,并通过此计算触发新事件。

但是,我想知道,由于有一个侦听器,最好是从这些乐器中公开IEnumerable<>方法,并使用yield return来返回数据,而不是触发事件。

我想知道是否有人知道这两种方法的差异。 特别是,我正在寻找最佳的可靠性,最佳的暂停/取消操作能力,最适合穿线,一般安全等。

另外,使用第二种方法是否仍然可以在单独的线程上运行IEnumerable循环? 其中许多仪器都受CPU限制,因此确保每个仪器都在不同的线程上是至关重要的。

这听起来像是Reactive Extensions的一个非常好的用例。 它有一点学习曲线,但简而言之,IObservable是IEnumerable的双重性。 IEnumerable要求您从中拉出,IObservable将其值推送到观察者。 几乎任何时候你需要在你的枚举器中阻塞,这是一个好的迹象,你应该扭转模式并使用推模型。 事件是一种方法,但IObservable具有更大的灵活性,因为它是可组合和线程感知的。

instrument.DataEvents
          .Where(x => x.SomeProperty == something)
          .BufferWithTime( TimeSpan.FromSeconds(1) )
          .Subscribe( x => DoSomethingWith(x) );

在上面的示例中,只要主题(工具)生成具有匹配SomeProperty的DataEvent并且将事件缓冲到1秒持续时间的批次中,就会调用DoSomethingWith(x)。

你可以做更多的事情,例如合并其他主题产生的事件或将通知指向UI线程等。不幸的是,文档目前相当薄弱,但有一些关于Matthew Podwysocki博客的好信息。 (虽然他的帖子几乎完全提到了JavaScript的Reactive Extensions,但它几乎都适用于.NET的Reactive Extensions。)

这是一个非常接近的电话,但我认为在这种情况下我会坚持使用事件模型,主要的决策者认为未来的维护程序员不太可能理解产量概念。 此外,yield表示处理每个硬件请求的代码与生成处理请求的代码在同一个线程中。 这很糟糕,因为它可能意味着您的硬件必须等待消费者代码。

说到消费者,另一种选择是生产者/消费者队列。 你的乐器都可以进入同一个队列,然后你的单个听众可以从那里弹出任何东西。

有一个非常根本的区别,推动与拉动。 拉模型(yield)是从仪器界面视图实现的更难的模型。 因为在客户端代码准备就绪之前,您必须存储数据。 当您推送时,客户端可能会或可能不会在其认为必要时进行存储。

但是,多线程场景中的大多数实际实现需要处理呈现数据所需的不可避免的线程上下文切换的开销。 而这通常是使用线程安全的有界队列来完成的。

Stephen Toub 博客讨论了一个阻塞队列,它使用yield关键字将IEnumerable实现为无限循环。 您的工作线程可以在出现新数据点时将其排队,并且计算线程可以使用具有阻塞语义的foreach循环将它们出列。

我认为事件和yield方法之间在绩效方面存在很大差异。 Yield是惰性评估的,因此它有机会发出生产线程停止的信号。 如果您的代码经过精心记录,那么维护也应该是一种清洗。

我的偏好是第三种选择,使用回调方法而不是事件(即使两者都涉及委托)。 您的生成器每次有数据时都会调用回调。 回调可以返回值,因此您的消费者可以通过每次检入数据来指示生产者停止或继续。

如果您拥有大量数据,此方法可以为您提供优化性能的位置。 在回调中,您锁定中性对象并将传入数据附加到集合中。 运行时内部在锁对象上使用就绪队列,因此这可以作为您的排队点。

这使您可以选择一个集合,例如具有预定义容量的List<T> ,即O(1)用于追加。 您还可以对消费者进行双重缓冲,将回调附加到“左”缓冲区,同时从“正确”缓冲区进行合并,依此类推。 这最大限度地减少了生产者阻塞和相关的错过数据的数量,这对于突发数据很方便。 当您改变螺纹数量时,您还可以轻松测量高水位标记和加工速率。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM