我读了ZeroMq guide,我偶然发现了以下内容:
你之间不能共享ØMQ套接字 线程。 ØMQ插座不是 线程安全的。从技术上讲,这是可能的 要做到这一点,但它需要信号量, 锁或互斥锁。这将使你的 应用缓慢而脆弱。唯一的 远离它的地方 线程之间的共享套接字在 需要做的语言绑定 像垃圾收集一样神奇 套接字。
以及后来:
请记住:除了创建它们的线程外,不要使用或关闭套接字。
我也明白ZeroMQ Context
是线程安全的。
如果一个类在.Net中注册另一个类的事件,则可以从与创建监听器的线程不同的线程调用此事件。
我认为只有两个选项可以从事件处理程序中通过ZeroMQ-Sockets调度内容:
Socket
/获取现有的ZeroMQ - Socket
for the threadhand - Socket
似乎0MQ-Guide不鼓励第一个,我不认为为每个线程创建一个新的ZeroMq-Socket是高性能/可行的方式。
我的问题:
在事件处理程序中通过0MQ发布消息的正确模式(它的方式是什么)是什么?
此外,该指南的作者在撰写时还考虑过.Net的ZeroMQ-Binding:
唯一的 远离它的地方 线程之间的共享套接字在 需要做的语言绑定 像垃圾收集一样神奇 插座。 ?
以下是一些强调我的问题/问题的示例代码:
Context
答案 0 :(得分:25)
你可以创建许多0MQ套接字,当然和你拥有的线程一样多。如果在一个线程中创建套接字,并在另一个线程中使用它,则必须在两个操作之间执行完整的内存屏障。其他任何东西都会导致libzmq出现奇怪的随机故障,因为套接字对象不是线程安全的。
有一些传统模式,虽然我不知道这些模式是如何专门针对.NET的:
答案 1 :(得分:7)
在.net framework v4及更高版本中,您可以使用并发集合来解决此问题。即生产者 - 消费者模式。多个线程(处理程序)可以将数据发送到线程安全队列,只有单个线程使用队列中的数据并使用套接字发送它。
这是一个想法:
sendQueue = new BlockingCollection<MyStuff>(new ConcurrentQueue<MyStuff>());
// concurrent queue can accept from multiple threads/handlers safely
MyHandler += (MyStuff stuffToSend) => sendQueue.Add(stuffToSend);
// start single-threaded data send loop
Task.Factory.StartNew(() => {
using(var socket = context.Socket()) {
MyStuff stuffToSend;
// this enumerable will be blocking until CompleteAdding is called
foreach(var stuff in sendQueue.GetConsumingEnumerable())
socket.Send(stuff.Serialize());
}
});
// break out of the send loop when done
OnMyAppExit += sendQueue.CompleteAdding;
答案 2 :(得分:2)
不要忘记查看inproc传输。使用inproc://套接字进行线程间通信可能很有用,并且有一个线程可以打开套接字与其他进程/服务器通信。
每个线程仍需要至少一个套接字,但inproc版本根本不需要IP网络层。