100% CPU usage with zeromq Push socket with 0 listeners
Created by: solatis
I originally submitted this as a StackOverflow question, but at this point I feel submitting this as an issue here is more appropriate.
I am currently in the process of implementing a communication pipeline between several processes using ZeroMQ, all using the Push/Pull mechanism. The pipeline starts with a 'ventilator' that generates tasks, and here is where my problem also starts: ZeroMQ seems to be using 100% CPU load when no workers are connected.
Here is the code in question, which attempts to send just one message:
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
As you can see, this code is extremely simple and just attempts to send the message "foo" to any subscriber. I would expect this code to queue this message in the background, but instead it appears to get into a never-ending loop with the send command; when I strace the process, this is what I see happening:
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
This is why I believe this might be a bug, or a problem in my code. There is an example in the zguide that is similar to what I'm trying to achieve: https://github.com/imatix/zguide/blob/master/examples/Haskell/taskvent.hs
In this example, they explicitly request user input to start sending (specifically, 'press enter when workers are ready') -- is this the way to work around this problem?
To elaborate, the following program (with a connected listener) works perfectly:
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)