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

我想要一个异步UDP服务器,以便可以立即检索和存储数据,这样我就不会错过任何请求(使用DatagramServer gevent提供的这部分很容易)。然后,我需要某种方式将请求串行发送到外部Web服务,但这种方式不会破坏UDP服务器的异步。

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

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

我需要的是有关运行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()

最佳答案

这是我的处理方式:

  • 编写一个以“队列”对象为参数的函数;此功能将连续处理队列中的项目。每个项目都应该是对Web服务的请求。
    此函数可能是模块级函数,而不是DatagramServer实例的一部分:
    def process_requests(q):
        while True:
            request = q.get()
            # do your magic with 'request'
            ...
    
  • 在您的DatagramServer中的
  • 中,使该函数在greenlet中运行(就像后台任务一样):
    self.__q = gevent.queue.Queue()
    self.__request_processing_greenlet = gevent.spawn(process_requests, self.__q)
    
  • 当您在DatagramServer实例中收到UDP请求时,将请求推送到队列
    self.__q.put(request)
    

  • 这应该做您想要的。您仍然在DatagramServer上调用“serve_forever”,没问题。

    10-05 20:50
    查看更多