Reputation: 189906
I want to create a PyZMQ eventloop in a background thread, and have it work correctly with both standalone Python scripts and IPython scripts. (IPython uses PyZMQ eventloops located in the main thread, so this is causing me problems and why I want to start a private ioloop in a background thread.)
I want to run code in Thread A while having the PyZMQ eventloop handle received data from a socket in Thread B. There are times in Thread A where I will need to wait for an event set in Thread B.
How can I get this to work? There seems to be something wrong if I try in IPython:
from zmq.eventloop import ioloop
import threading
class IOBackgroundLoop(object):
def __init__(self):
self._loop = None
self._thread = threading.Thread(target=self.run)
self._thread.daemon = True
self._started = threading.Event()
@property
def loop(self):
return self._loop
def run(self):
self._loop = ioloop.IOLoop()
self._loop.initialize()
self._loop.make_current()
self._started.set()
self._loop.start()
def start(self):
self._thread.start()
self._started.wait()
bkloop = IOBackgroundLoop()
bkloop.start()
for loop in [bkloop.loop, ioloop.IOLoop.instance()]:
print "%s running: %s" % (loop, loop._running)
This prints out two separate instances of IOLoop, but if I go to use it, it doesn't seem to work. I can't think of a small example program to demonstrate this; I've tried with a timeout function:
import time
def print_timestamp(key):
print "%s: %s" % (time.time(), key)
for loop in [bkloop.loop, ioloop.IOLoop.instance()]:
loop.add_timeout(bkloop.loop.time() + 1.0, lambda: print_timestamp("hi from %s" % loop))
print_timestamp("here")
time.sleep(2.0)
print_timestamp("there")
and I get this as a result (no "hi":
1412889057.68: here
1412889059.68: there
1412889059.68: here
1412889061.68: there
Then when I hit another shift+Enter, I get
1412889061.68: hi from <zmq.eventloop.ioloop.ZMQIOLoop object at 0x000000000467E4E0>
which is the IOLoop object from the main thread, but my private instance IOLoop never prints hi.
What could I be doing wrong?
Upvotes: 1
Views: 351
Reputation: 189906
Argh, I just noticed this in the tornado docs:
Note that it is not safe to call
add_timeout
from other threads. Instead, you must useadd_callback
to transfer control to theIOLoop
's thread, and then calladd_timeout
from there.
It also appears as though the zmq.eventloop.zmqstream
needs to be setup in the same thread as the ioloop for it to work properly.
Upvotes: 1