gpt4 book ai didi

c++ - 每个线程或每个调用一个 ZeroMQ 套接字?

转载 作者:太空狗 更新时间:2023-10-29 23:43:45 25 4
gpt4 key购买 nike

众所周知,一个ZeroMQ socket shall not be shared among application threads . context_t但是实例可以。

我有一个多线程应用程序,我希望每个线程不时与 交换消息。 REQ/REP -socket 交易对手(事件、异常等),取决于他们在做什么(他们在做非 ZeroMQ 的事情)。

给我发消息 REQ/REP -socket 我使用以下函数(半 C++ 半伪代码):

sendMessage:

bool sendMessage(std::string s)
{
zmq::socket_t socket(globalContext(), ZMQ_REQ);
socket.connect("ipc://http-concentrator");

zmq::message_t message(s.size());
memcpy(message.data(), s.data(), s.size());
if (!socket.send(message))
return false;

// poll on socket for POLLIN with timeout

socket.recv(&message);
// do something with message

return true;
}

需要时从每个线程调用此函数。它创建一个本地套接字、连接、发送消息并接收响应。在退出时,套接字被断开并移除(至少我假设它是关闭的)。

这样,我就不需要费心在我的每个线程中维护一个套接字。这是以每次调用此函数时创建和连接为代价的。

我已经强调了这段代码,我没有看到重用一个套接字和这个重新连接实现之间有太大区别。 (我每秒有 20k REP/REQ 个事务,包括一个 JSON 解码/编码,在用例的两侧)

问:有没有更正确的 ZeroMQ 方式来做到这一点?

最佳答案

Nota Bene: this answer was posted before O/P was changed from 20k TPS to 140k TPS on ipc:// transport-class

Q: Is there a more correct ZeroMQ-way of doing this?

A:Not easy to say what is "this" and what are the parameters of the "correctness"-metric



鉴于此,以下几点将更普遍适用于系统设计阶段的推理:

资源利用开销避免

这一点是一把双刃剑。一些开销总是与 的基础设施元素设置和处置(是的,甚至关闭和拆除)相关联。 REQ -AccessPoint 到 REQ/REP -pattern 和相关的基于套接字的传输类对 REQ 施加了一些显着的开销。 - 端主机和 REP -边。

公平地说,您已经注意到,您在大约 20k TPS 的水平上对此进行了一些定量测试,并且没有观察到这种方法的任何不利影响。不清楚的是,是否在同一 SUT(被测系统)上还对任何其他场景进行了体内测试,以便为每个各自设计的比较提供一些基线(并允许确定开销的差异)本身)。

虽然一个设计良好的框架对用户维护的代码隐藏了这部分系统内部行为,但这并不意味着它是一种廉价的,更少的免费处理。

很明显, 中有一些在幕后执行的工作。 Context() -instance thread(s) ( ... 是的,这里的复数是正确的,因为一些高性能代码可能会受益于每个 Context() 实例使用多个 I/O 线程并通过明确定义的积极影响工作负载分布模式套接字与其各自的 I/O 线程处理程序之间的关联映射(以便以某种方式平衡,如果不能确定性地平衡,预期的 I/O 吞吐量,包括所有相关的开销)。

如果仍然有疑问,请永远记住,命令式编程风格的函数或面向对象的方法主要是外部调用者的受害者,外部调用者决定何时以及多久这样的“ en-slaved ”代码执行单元被调用并被执行。函数/方法没有任何自然的方法来限制(抑制)它自己从外部调用者调用的频率,而且健壮的设计不能仅仅依赖乐观的假设,这样的调用不会更多通常比 XYZ-k TPS(上面引用的 20k 可能适合体外测试,但实际部署可能会改变几个数量级(无论是人为的 - 在测试期间,或者不是 - 在某些高峰时段或用户(系统) )- panic 或由于某些技术错误或硬件故障(我们都听说过很多次关于 NIC 卡淹没 L1/L2 流量超出所有可以想象的限制等 - 我们只是不知道,也不知道,何时/何地下次还会发生)。

避免阻塞风险

提到的 REQ/REP 可扩展的正式通信模式以其陷入外部无法解决的分布式内部死锁的风险而闻名。这总是需要避免的风险。缓解策略可能取决于实际用例的风险值(value)(需要认证医疗器械、金融科技用例、控制回路用例、学术研究论文代码或私有(private)爱好玩具)。

Ref.: REQ/REP Deadlocks >>> https://stackoverflow.com/a/38163015/3666197



Fig.1: 为什么使用天真的是错误的 REQ/REP [App1] 时的所有情况 in_WaitToRecvSTATE_W2R + [App2] in_WaitToRecvSTATE_W2R 主要是 REQ-FSA/REP-FSA 不可挽救的分布式相互死锁(两个有限状态自动机中的每一个都等待“另一个”移动)并且永远不会到达“下一个” in_WaitToSendSTATE_W2S 内部状态。
               XTRN_RISK_OF_FSA_DEADLOCKED ~ {  NETWORK_LoS
: || NETWORK_LoM
: || SIG_KILL( App2 )
: || ...
: }
:
[App1] ![ZeroMQ] : [ZeroMQ] ![App2]
code-control! code-control : [code-control ! code-control
+===========!=======================+ : +=====================!===========+
| ! ZMQ | : | ZMQ ! |
| ! REQ-FSA | : | REP-FSA! |
| !+------+BUF> .connect()| v |.bind() +BUF>------+! |
| !|W2S |___|>tcp:>---------[*]-----(tcp:)--|___|W2R |! |
| .send()>-o--->|___| | | |___|-o---->.recv() |
| ___/ !| ^ | |___| | | |___| ^ | |! \___ |
| REQ !| | v |___| | | |___| | v |! REP |
| \___.recv()<----o-|___| | | |___|<---o-<.send()___/ |
| !| W2R|___| | | |___| W2S|! |
| !+------<BUF+ | | <BUF+------+! |
| ! | | ! |
| ! ZMQ | | ZMQ ! |
| ! REQ-FSA | | REP-FSA ! |
~~~~~~~~~~~~~ DEADLOCKED in W2R ~~~~~~~~ * ~~~~~~ DEADLOCKED in W2R ~~~~~~~~~~~~~
| ! /\/\/\/\/\/\/\/\/\/\/\| |/\/\/\/\/\/\/\/\/\/\/! |
| ! \/\/\/\/\/\/\/\/\/\/\/| |\/\/\/\/\/\/\/\/\/\/\! |
+===========!=======================+ +=====================!===========+

关于c++ - 每个线程或每个调用一个 ZeroMQ 套接字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41941702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com