我已经使用python请求库有一段时间了,最近需要异步发出请求,这意味着我想发送HTTP请求,让我的主线程继续执行,并在请求返回时调用回调。
自然地,我被引导到请求库(https://github.com/kennethreitz/grequests),但我对行为感到困惑。例如:
import grequests
def print_res(res):
from pprint import pprint
pprint (vars(res))
req = grequests.get('http://www.codehenge.net/blog', hooks=dict(response=print_res))
res = grequests.map([req])
for i in range(10):
print i
上面的代码将产生以下输出:
<...large HTTP response output...>
0
1
2
3
4
5
6
7
8
9
在HTTP响应可用之前,grerequests .map()调用显然会阻塞。似乎我误解了这里的"异步"行为,grerequests库只是用于并发地执行多个HTTP请求,并将所有响应发送到单个回调。这准确吗?
.map()
意味着并行运行多个url的检索,并且确实会等待这些任务完成(gevent.joinall(jobs)
被调用)。
使用.send()
来生成作业,使用Pool
实例:
req = grequests.get('http://www.codehenge.net/blog', hooks=dict(response=print_res))
job = grequests.send(req, grequests.Pool(1))
for i in range(10):
print i
如果没有池,.send()
调用仍然会阻塞,但只会阻塞gevent.spawn()
调用。
如果您不想使用grequests
,您可以使用requests
+标准库中的threading
模块实现带有回调的请求。它实际上真的很简单,如果你想做的只是发送带有回调的请求,那么API比grequests
提供的API更好。
from threading import Thread
from requests import get, post, put, patch, delete, options, head
request_methods = {
'get': get,
'post': post,
'put': put,
'patch': patch,
'delete': delete,
'options': options,
'head': head,
}
def async_request(method, *args, callback=None, timeout=15, **kwargs):
"""Makes request on a different thread, and optionally passes response to a
`callback` function when request returns.
"""
method = request_methods[method.lower()]
if callback:
def callback_with_args(response, *args, **kwargs):
callback(response)
kwargs['hooks'] = {'response': callback_with_args}
kwargs['timeout'] = timeout
thread = Thread(target=method, args=args, kwargs=kwargs)
thread.start()
你可以验证它像JS中的AJAX调用一样工作:你在另一个线程上发送请求,在主线程上做一些事情,当请求返回时调用回调。这个回调只输出响应内容。
async_request('get', 'http://httpbin.org/anything', callback=lambda r: print(r.json()))
for i in range(10):
print(i)
创建一个请求列表,然后使用.imap
发送它们:
event_list = [grequests.get(url_viol_card, params={"viol": i},
session=session) for i in print_ev_list]
for r in grequests.imap(event_list, size=5):
print(r.request.url)
-
session
是requests.Session()
对象(可选) -
size=5
同时发送5个请求:一旦其中一个请求完成,就发送下一个请求 - 在这个例子中,当任何请求(无序)完成时,它的url被打印出来