Gevent通过非阻塞joinall()增量处理

0 投票
1 回答
1273 浏览
提问于 2025-04-17 05:56

在这里,我想对我的设置做一些修改。

我希望在向我的服务器发出一个请求时,能够同时从多个API调用中获取响应。我想把这些API调用的结果合并起来,然后作为一个响应返回给前端。到这里为止,基本上所有的内容都和gevent文档中的例子差不多。不过这里有个关键点,我想以增量的方式返回响应,也就是说,如果第一个API调用返回了结果,我就会立即把这个结果返回给前端,然后再等待其他API调用的结果,并把它们也在同一个请求中返回给前端。

我尝试通过代码来实现这个功能,但我不知道该如何进行设置。gevent的.joinall().join()会一直阻塞,直到所有的绿色线程(greenlets)都完成响应。

有没有什么方法可以在这个设置中继续使用gevent呢?

我这里使用的代码可以在这个链接找到:https://bitbucket.org/denis/gevent/src/tip/examples/concurrent_download.py。在最后的语句中,.joinall()会等待所有的URL都完成响应,我希望它能够非阻塞,这样我就可以在回调函数print_head()中处理响应,并以增量的方式返回它们。

#!/usr/bin/python
# Copyright (c) 2009 Denis Bilenko. See LICENSE for details.

"""Spawn multiple workers and wait for them to complete"""

urls = ['http://www.google.com', 'http://www.yandex.ru', 'http://www.python.org']

import gevent
from gevent import monkey

# patches stdlib (including socket and ssl modules) to cooperate with other greenlets
monkey.patch_all()

import urllib2


def print_head(url):
    print ('Starting %s' % url)
    data = urllib2.urlopen(url).read()
    print ('%s: %s bytes: %r' % (url, len(data), data[:50]))

jobs = [gevent.spawn(print_head, url) for url in urls]

gevent.joinall(jobs)

1 个回答

1

如果你想从多个绿色线程(greenlets)中收集结果,那么你需要修改一下 print_head() 这个函数,让它返回结果。然后你可以使用 .get() 方法来把所有结果收集起来。

把这个放在 joinall() 之后:

total_result = [x.get() for x in jobs]

其实在这种情况下,joinall() 这个步骤是可以省略的。

如果 print_head() 的样子是这样的:

def print_head(url):
    print ('Starting %s' % url)
    return urllib2.urlopen(url).read()

那么 total_result 就会是一个大小为3的列表,里面包含了所有请求的响应。

撰写回答