2014-10-16 81 views
1

我试图将一个简单的同步服务器转换为异步版本,服务器收到post requestes并从外部web服务(亚马逊sqs)获取响应。这里的syncronous代码在Tornado web服务器中正确使用协程

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) 

阅读旋风文档和这里的一些线程我使用协同程序使用此代码结束:

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它是从伯特接口和queue.write(msg)检索队列对象返回已写入队列

+0

什么'_sqs_send_queue'在你的榜样?直到从亚马逊检索到响应之后,该调用才会返回吗? – dano 2014-10-16 17:37:10

回答

0

tornado依赖于你将所有的I/O是非阻塞的消息。只需在gen.Task之前使用与之前使用的代码相同的代码,根本不会提高性能,因为I/O本身仍然会阻止事件循环。此外,您需要将post方法作为协程,并使用yield调用_send_parking_spots_requests,以使代码正常运行。所以,一个“正确”的解决方案将是这个样子:

@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将需要一些API发送使用您的要求非阻塞I/O,当一个反应是执行callback接收。如果不知道原始示例中的queue究竟是什么,我无法详细说明如何在您的案例中实施。

编辑:假设你正在使用boto,你可能想看看bototornado,它实现the 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. 
+0

好的,所以主要的问题似乎是任务执行的函数必须是非阻塞的。顺便说一下,我不知道bototornado,这似乎是我的问题的解决方案 – supernovae 2014-10-16 23:48:50

+0

@ user1030148正确。与使用线程或类似'gevent'的不同,通常不会在'tornado'中发生从同步到异步的转换,而无需在一定程度上重新编写现有代码。 – dano 2014-10-16 23:54:56

+0

最后我用了你写的模块(botornado)。然而,当我在寻找替代品时,我发现了这个有趣的[文章](http://blog.joshhaas.com/2011/06/marrying-boto-to-tornado-greenlets-bring-them-together/)。对于那些正在与龙卷风和博多斗争的人来说,这可能是有用的 – supernovae 2014-10-18 08:10:19

相关问题