【发布时间】:2014-08-10 03:00:46
【问题描述】:
我目前正在使用 ZeroMQ 实现多个进程之间的通信管道,所有进程都使用 Push/Pull 机制。管道从生成任务的“呼吸机”开始,这也是我的问题开始的地方:当没有连接任何工作人员时,ZeroMQ 似乎正在使用 100% 的 CPU 负载。
这是有问题的代码,它试图只发送一条消息:
module Main where
import System.ZMQ4.Monadic
import Data.ByteString.Char8 (pack)
main :: IO ()
main = do
runZMQ $ do
publisher <- socket Push
bind publisher "tcp://*:10150"
send publisher [] (pack "foo")
close publisher
如您所见,这段代码非常简单,只是尝试将消息“foo”发送给任何订阅者。我希望这段代码在后台排队这条消息,但它似乎进入了send 命令的永无止境的循环。在套接字上设置高水位线无效。
zguide 中有一个与我想要实现的示例类似的示例:https://github.com/imatix/zguide/blob/master/examples/Haskell/taskvent.hs
在这个例子中,他们明确要求用户输入开始发送(具体来说,'当工作人员准备好时按 Enter')——这是他们解决这个问题的方法吗?
谁能告诉我我在这里做错了什么,或者解决这个问题的最佳方法是什么?
编辑
详细来说,以下程序(带有连接的侦听器)可以完美运行:
module Main where
import System.ZMQ4.Monadic
import Data.ByteString.Char8 (pack, unpack)
import Control.Applicative ((<$>))
main :: IO ()
main = do
runZMQ $ do
publisher <- socket Push
receiver <- socket Pull
bind publisher "tcp://*:10150"
connect receiver "tcp://127.0.0.1:10150"
send publisher [] (pack "foo")
message <- unpack <$> receive receiver
liftIO $ putStrLn ("received data: " ++ message)
这会按预期打印出接收到的数据。
编辑 2
使用 strace,我能够破译 zeromq 显然处于轮询/选择无限循环中:
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
--- SIGVTALRM {si_signo=SIGVTALRM, si_code=SI_TIMER, si_pid=0, si_uid=0, si_value=0} ---
rt_sigreturn() = 1
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
poll([{fd=8, events=POLLIN}], 1, 0) = 0 (Timeout)
select(9, [], [8], NULL, NULL) = 1 (out [8])
--- SIGVTALRM {si_signo=SIGVTALRM, si_code=SI_TIMER, si_pid=0, si_uid=0, si_value=0} ---
rt_sigreturn() = 1
这种模式会不断重复。
【问题讨论】:
-
我也将此作为库开发人员的实际问题提交:github.com/twittner/zeromq-haskell/issues/55