简体   繁体   中英

Python tornado - how to create a blocking call without stopping the loop?

I am using ZMQ streams, which are based around their own implementation of tornado's IOLoop. I am running into a problem where I want to have synchronous behavior, yet IOLoop is forcing me into asynchronous execution. Here is the specifics:

I have a class which is solely responsible for camera settings (camera is in a different process):

class HamSettingsManager(object):
    ''' 
        This class makes sure the camera is set to the requested settings.
    '''
    def __init__(self, blabla, loop=None):
        self._msg = messaging.CamSettings(blabla)

        self._loop = loop or zmq.eventloop.ioloop.IOLoop()
        self._sub = messaging.StreamFactory.sub_stream(
            messaging.channel_map.DI().settings,
            loop=self._loop,
            on_recv=self._on_settings)

        self._pub = messaging.StreamFactory.pub_stream(
            messaging.channel_map.DI().update_settings,
            loop=self._loop)

    @tornado.gen.coroutine
    def set_settings(self):
        self._pub.send(self._msg.SerializeToString())
        self._new_settings = True
        self._changed = None
        while self._new_settings:
            log.debug("Waiting for camera settings to take effect.")
            yield tornado.gen.Task(self._loop.add_timeout, time.time() + 0.05)

    def _on_settings(self, data):
        msg = messaging.HamSettings()
        msg.ParseFromString(data[-1])

        if msg == self._msg:
            self._new_settings = False
        else:
            if not self._new_settings:
                log.warning("Someone has changed the camera settings underneath the aligner.")
                self._changed = time.time()

            log.debug("Settings not as expected, resending")
            log.debug("Current settings: \n%s" % msg)
            log.debug("Expected settings: \n%s" % self._msg)
            self._pub.send(self._msg.SerializeToString())

What I expect to happen is set_settings will ONLY return once the settings have taken effect, but what actually happens is the execution simply continues as if I spawned a thread. What is the proper way waiting in the IOLoop?

You can't create a blocking call without stopping the event loop; that's what "blocking" means. As a coroutine, set_settings returns a Future immediately; the caller is responsible for waiting for that Future to be resolved. In general, this means that anything that calls it must also be a coroutine (or otherwise asynchronous) and use yield mgr.set_settings() instead of a simple call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM