我正在设计一个 GUI 来显示市场数据。目前,我有多个使用相同数据但显示不同方面的窗口。我试图找出构建这个系统的最佳方法。
我有一个市场数据生产者和多个消费者,它们向生产者注册回调。当生产者准备好数据时,它会遍历消费者列表并通过回调将数据分发给每个消费者。我不确定这是否是分发数据的最佳方法。每个消费者必须等待前一个消费者完成回调处理才能获取其数据。
有没有一种方法可以让所有消费者同时或以最小的延迟获取数据?我正在使用 C# 4.0,想知道是否有任何语言功能可以实现这一点。
我正在设计一个 GUI 来显示市场数据。目前,我有多个使用相同数据但显示不同方面的窗口。我试图找出构建这个系统的最佳方法。
我有一个市场数据生产者和多个消费者,它们向生产者注册回调。当生产者准备好数据时,它会遍历消费者列表并通过回调将数据分发给每个消费者。我不确定这是否是分发数据的最佳方法。每个消费者必须等待前一个消费者完成回调处理才能获取其数据。
有没有一种方法可以让所有消费者同时或以最小的延迟获取数据?我正在使用 C# 4.0,想知道是否有任何语言功能可以实现这一点。
对于这种情况,您应该使用 RabbitMQ 或 MSMQ 等队列。它们是此类发布者/订阅者操作的最佳选择。
如果这不是一个选项,您可以使用线程触发回调或将它们设置为 WCF 触发并忘记调用 (OneWay)。
您可以通过使用单独的BlockingCollection
每个消费者来寻求一个相当简单的解决方案。
生产者线程只需要一个它自己管理List<>
的队列。BlockingCollection
当生产者线程产生一个项目时,它只需要将它添加到列表中的每个队列中,使用BlockingCollection.Add()
. 注意:这是多次排队的同一个项目- 每个消费者队列一次。
项目类型应该是不可变的引用类型 - 然后在消费者之间共享是安全的,并且开销只是每个消费者队列中的引用。
这不是最有效的路线,因为它需要每个消费者排队,但我不认为这太糟糕了,除非排队很大。不过,它很容易理解和实施。
BlockingCollection
当没有更多数据时,A可以很容易地告诉消费者线程,以便它们可以干净地退出。
生产者线程调用BlockingCollection.CompleteAdding()
以向消费线程发出信号,当没有更多数据时它们应该退出。
同时,所有消费线程需要做的是(假设queue
是他们的 BlockingCollection 队列):
foreach (var item in queue.GetConsumingEnumerable())
{
... process item
}
而已。当没有更多数据时消费者会自动阻塞在循环中,当没有更多数据并且生产者调用时foreach
他们会自动退出。foreach
CompleteAdding()
如果从它们自己的线程(很可能是线程池线程)调用每个注册的回调很重要,那么这很容易做到:
public class Foo
{
private HashSet<Action> callbacks = new HashSet<Action>();
public event Action MyEvent
{
add
{
callbacks.Add(value);
}
remove
{
callbacks.Remove(value);
}
}
private void FireMyEvent()
{
foreach (var action in callbacks)
{
ThreadPool.QueueUserWorkItem(o => { action(); });
}
}
}