具有阻止请求的Gevent异步服务器

时间:2014-06-02 07:10:29

标签: python sockets asynchronous gevent

我认为Gevent是一个非常常见的用例。我需要一个侦听请求的UDP服务器,并根据请求向外部Web服务提交POST。外部Web服务基本上一次只允许一个请求。

我希望有一个异步UDP服务器,以便可以立即检索和存储数据,这样我就不会错过任何请求(这部分很容易通过DatagramServer gevent提供)。然后我需要一些方法来串行地向外部Web服务发送请求,但这样做不会破坏UDP服务器的异步。

我首先尝试使用猴子修补所有内容,而我最终得到的是一个快速解决方案,但我对外部Web服务的请求不受任何速率限制,导致错误。

似乎我需要的是一个非阻塞工作者,以便在UDP服务器将任务添加到非阻塞工作者正在工作的队列中时,以串行方式向外部Web服务发送请求。

我需要的是有关运行gevent服务器以及其他任务(特别是队列)的其他greenlet的信息。我一直在使用DatagramServer的serve_forever功能,并认为我需要使用start方法,但是我们还没有找到有关它如何使用的信息合在一起。

谢谢,

修改

答案非常有效。我已经使用@mguijarr的答案调整了UDP server example代码,为我的用例提供了一个工作示例:

from __future__ import print_function
from gevent.server import DatagramServer
import gevent.queue
import gevent.monkey
import urllib

gevent.monkey.patch_all()

n = 0

def process_request(q):
    while True:
        request = q.get()
        print(request)
        print(urllib.urlopen('https://test.com').read())


class EchoServer(DatagramServer):
    __q = gevent.queue.Queue()
    __request_processing_greenlet = gevent.spawn(process_request, __q)

    def handle(self, data, address):
        print('%s: got %r' % (address[0], data))
        global n
        n += 1
        print(n)
        self.__q.put(n)
        self.socket.sendto('Received %s bytes' % len(data), address)


if __name__ == '__main__':
    print('Receiving datagrams on :9000')
    EchoServer(':9000').serve_forever()

1 个答案:

答案 0 :(得分:1)

我将如何做到这一点:

  1. 编写一个带有"队列的函数"对象作为参数;此函数将持续处理队列中的项目。每个项目都应该是对Web服务的请求。 此函数可以是模块级函数,而不是DatagramServer实例的一部分:

    def process_requests(q):
        while True:
            request = q.get()
            # do your magic with 'request'
            ...
    
  2. 在您的DatagramServer中,
  3. 使函数在greenlet中运行(如后台任务):

    self.__q = gevent.queue.Queue()
    self.__request_processing_greenlet = gevent.spawn(process_requests, self.__q)
    
  4. 在DatagramServer实例中收到UDP请求时,将请求推送到队列

    self.__q.put(request)    
    
  5. 这应该做你想要的。你仍然打电话给'serve_forever'在DatagramServer上,没问题。

相关问题