在Tornado Web服务器中正确使用协同程序

时间:2014-10-16 17:32:49

标签: python asynchronous tornado

我正在尝试将简单的同步服务器转换为异步版本,服务器接收邮件请求,并从外部Web服务(amazon sqs)检索响应。这是同步代码

def post(self):

    zoom_level = self.get_argument('zoom_level')
    neLat = self.get_argument('neLat')
    neLon = self.get_argument('neLon')
    swLat = self.get_argument('swLat')
    swLon = self.get_argument('swLon')
    data = self._create_request_message(zoom_level, neLat, neLon, swLat, swLon)

    self._send_parking_spots_request(data)

    #....other stuff

def _send_parking_spots_request(self, data):

    msg = Message()
    msg.set_body(json.dumps(data))
    self._sqs_send_queue.write(msg)

在这里阅读Tornado文档和一些线程我使用coroutines结束了这段代码:

def post(self):

    zoom_level = self.get_argument('zoom_level')
    neLat = self.get_argument('neLat')
    neLon = self.get_argument('neLon')
    swLat = self.get_argument('swLat')
    swLon = self.get_argument('swLon')
    data = self._create_request_message(zoom_level, neLat, neLon, swLat, swLon)
    self._send_parking_spots_request(data)
    self.finish()

@gen.coroutine
def _send_parking_spots_request(self, data):

    msg = Message()
    msg.set_body(json.dumps(data))
    yield gen.Task(write_msg, self._sqs_send_queue, msg)

def write_msg(queue, msg, callback=None):
    queue.write(msg)

使用围攻比较性能我得知第二个版本甚至比原版更差,所以可能有一些关于协同程序和Torndado异步编程的东西,我根本不理解。 你能帮帮我吗?

编辑: self._sqs_send_queue这是从boto接口检索到的队列对象,queue.write(msg)返回已写入队列的消息

1 个答案:

答案 0 :(得分:0)

tornado依赖于您将所有I / O转换为非阻塞。简单地在gen.Task内部使用之前使用的相同代码根本不会提高性能,因为I / O本身仍然会阻止事件循环。此外,您需要将post方法设为协程,并使用_send_parking_spots_requests调用yield以使代码正常运行。因此,“正确”的解决方案看起来像这样:

@gen.coroutine
def post(self):
    ...
    yield self._send_parking_spots_request(data)  # wait (without blocking the event loop) until the method is done
    self.finish()

@gen.coroutine
def _send_parking_spots_request(self, data):

    msg = Message()
    msg.set_body(json.dumps(data))
    yield gen.Task(write_msg, self._sqs_send_queue, msg)

def write_msg(queue, msg, callback=None):
    yield queue.write(msg, callback=callback)  # This has to do non-blocking I/O.

在此示例中,queue.write需要是一些使用非阻塞I / O发送请求的API,并在收到响应时执行callback。如果不确切知道原始示例中的queue究竟是什么,我无法准确指出在您的案例中如何实现。

修改:假设您使用的是boto,您可能需要查看实施bototornadothe exact same API I described above

def write(self, message, callback=None):
    """
    Add a single message to the queue.
    :type message: Message
    :param message: The message to be written to the queue
    :rtype: :class:`boto.sqs.message.Message`
    :return: The :class:`boto.sqs.message.Message` object that was written.