-
Notifications
You must be signed in to change notification settings - Fork 636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PUBhandler can not be used with multiprocessing #710
Comments
You cannot pass zmq contexts or sockets across the fork boundary that happens when you instantiate a subprocess with multiprocessing. You have to make sure that you create your Context after you are in the subprocess. In your example, you are creating the LogWorker in the main process, then creating a new process to run just one method of the Worker. Since it looks like you don't actually have any use for the LogWorker in your main process, I would probably recommend waiting to instantiate the object until you reach the subprocess, e.g.: def work():
worker = LogWorker(port)
worker.log_worker()
workers = [ Process(target=work) for _ in range(n) ] In this way, it doesn't matter where you instantiate the logger in the LogWorker's lifecycle, because the LogWorker object only exists in the subprocess. |
thanks for you answer, i am not test but i think you are right ! A socket is passed to PUBhandler in MyLogger._construct_sock_handler method in main process, and then calling the same logger's method, for example logger.info which need the socket to send record in the logger.handler.emit method in subprocess causes the problem. I implements a handler which only takes tcp address (don't take socket) as parameter to solve the problem for my project , and it works .
|
Glad it works. |
thank you :-) |
Hi - i run into the same issue, i was not aware of this behaviour, although it totally makes sense reading @minrk's detailed explanation. I have a situation when multiple subprocesses need to send messages over the same publisher. What would be your recommendation in that case? An immediate solution would be sending back the messages to the parent (e.g. through a Pipe) - but is it possible to avoid this overhead and have a straight usage of the same publisher instance across multiple subprocesses? Thank you, |
The zmq solution would be use a proxy device, so each subprocess sends messages to a single device, and subscribers connect to the same device. The code of your publishers is identical to what it would be without the device (still a zmq PUB socket), except that the PUB socket connects to the relay, rather than binding itself. For instance: from multiprocessing import Process
import os
import time
import zmq
N_WORKERS = 4
N_MSGS = 5
PROXY_SUB_URL = 'ipc://proxy-internal'
PROXY_PUB_URL = 'tcp://127.0.0.1:5556'
def publisher():
ctx = zmq.Context()
pub = ctx.socket(zmq.PUB)
pub.connect(PROXY_SUB_URL)
pid = os.getpid()
for i in range(N_MSGS):
time.sleep(1)
pub.send(b'%i:%i' % (pid, i))
print('worker %i done' % pid)
def proxy():
ctx = zmq.Context()
sub = ctx.socket(zmq.SUB)
sub.subscribe(b'')
sub.bind(PROXY_SUB_URL)
pub = ctx.socket(zmq.PUB)
pub.bind(PROXY_PUB_URL)
try:
zmq.proxy(sub, pub)
except KeyboardInterrupt:
return
def subscriber():
ctx = zmq.Context()
sub = ctx.socket(zmq.SUB)
sub.subscribe(b'')
sub.connect(PROXY_PUB_URL)
for i in range(N_MSGS * N_WORKERS):
print('subscriber received %s' % sub.recv_string())
workers = [ Process(target=publisher) for i in range(N_WORKERS) ]
[ w.start() for w in workers ]
proxy_proc = Process(target=proxy)
proxy_proc.start()
subscriber()
proxy_proc.terminate() |
Fantastic, thanks a lot @minrk! |
I have a class 'MyLogger' for sending messages to log server by using PUBhandler. A exception raised when MyLogger is instanced in
LogWorker.__init__()
method (like version 1), however, it is ok if MyLogger is instanced inLogWorker.log_worker()
method (version 2). any suggestions would be appreciated.The text was updated successfully, but these errors were encountered: