Python中如何使用gevent进行异步请求并获取返回值

import gevent.monkey
gevent.monkey.patch_socket()

import gevent
import urllib2
import simplejson as json

def fetch(pid):
response = urllib2.urlopen(‘http://json-time.appspot.com/time.json’)
result = response.read()
json_result = json.loads(result)
datetime = json_result[‘datetime’]
print 'Process ', pid, datetime
return json_result[‘datetime’]

def asynchronous():
threads = []
for i in range(1,10):
threads.append(gevent.spawn(fetch, i))
gevent.joinall(threads)

我想得到 fetch 里面那个 return 的返回值,在 gevent.spawn 的情况下怎么才能得到 spawn 的函数里 return 的值啊
Python中如何使用gevent进行异步请求并获取返回值


8 回复
import gevent
from gevent import monkey
import requests

# 打补丁让标准库支持异步
monkey.patch_all()

def fetch_url(url):
    """异步获取单个URL的内容"""
    try:
        response = requests.get(url, timeout=5)
        return {
            'url': url,
            'status': response.status_code,
            'content': response.text[:100]  # 只取前100字符
        }
    except Exception as e:
        return {
            'url': url,
            'error': str(e)
        }

def async_fetch_urls(url_list):
    """并发获取多个URL"""
    # 创建协程任务
    jobs = [gevent.spawn(fetch_url, url) for url in url_list]
    
    # 等待所有协程完成
    gevent.joinall(jobs)
    
    # 获取所有结果
    results = [job.value for job in jobs]
    return results

if __name__ == "__main__":
    # 测试URL列表
    urls = [
        'https://httpbin.org/get',
        'https://api.github.com',
        'https://www.python.org'
    ]
    
    # 执行异步请求
    results = async_fetch_urls(urls)
    
    # 打印结果
    for result in results:
        print(f"URL: {result.get('url')}")
        if 'status' in result:
            print(f"  Status: {result['status']}")
            print(f"  Preview: {result['content']}")
        else:
            print(f"  Error: {result['error']}")
        print("-" * 50)

核心要点:

  1. monkey.patch_all() - 必须调用这个来让标准库(如requests)支持异步
  2. gevent.spawn() - 创建协程任务,不立即执行
  3. gevent.joinall() - 等待所有协程执行完成
  4. job.value - 获取协程的返回值

高级用法:使用gevent的Pool控制并发数:

from gevent.pool import Pool

def fetch_with_pool(urls, concurrency=3):
    """使用连接池控制并发数"""
    pool = Pool(concurrency)
    results = pool.map(fetch_url, urls)
    return results

# 使用示例
urls = ['https://httpbin.org/get'] * 10  # 10个相同请求
results = fetch_with_pool(urls, concurrency=5)  # 最多5个并发

关键提醒:

  • gevent是基于协程的异步,不是多线程/多进程
  • 所有协程在同一个线程中运行
  • I/O阻塞时自动切换协程
  • 适合I/O密集型任务,不适合CPU密集型

一句话建议:用gevent.spawn创建协程,gevent.joinall等待结果,job.value获取返回值。

或者说,我并不太理解在并发执行函数时怎么能得到每个函数的返回值? 不用 gevent 有别的方法吗

这么简单问题还用问?
import queue

q = queue.Queue(maxsize=0)

把 return 改成

q.put( json_result[‘datetime’])

用 q.get()一个一个取,或者 list(q.queue) 一起取

我就是这么取的,只是想知道 return 能不能 直接得到


你 return 给谁呀?
那样就成了顺序调用无法并发了。

嗯嗯,我理解一点了,谢谢

from gevent import monkey
monkey.patch_socket()
monkey.patch_ssl()
import gevent
import requests
import simplejson as json
from tornado import gen

.coroutine
def fetch(pid):
response = requests.get(‘https://www.baidu.com’)
result = response.text
# json_result = json.loads(result)
# datetime = json_result[‘datetime’]
print('Process ', result)
raise gen.Return(result)
# return result

def asynchronous():
threads = []
for i in range(1,10):
threads.append(gevent.spawn(fetch, i))
gevent.joinall(threads)

可以这样

回到顶部