【问题标题】:In what way is grequests asynchronous?grequests 以什么方式异步?
【发布时间】:2013-04-07 14:25:28
【问题描述】:

我已经使用python requests 库有一段时间了,最​​近需要异步发出请求,这意味着我想发送 HTTP 请求,让我的主线程继续执行,并有一个回调请求返回时调用。

当然,我被引导到 grequests 库 (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

grequests.map() 调用显然会阻塞,直到 HTTP 响应可用。似乎我在这里误解了“异步”行为,而 grequests 库仅用于同时执行多个 HTTP 请求并将所有响应发送到单个回调。这是准确的吗?

【问题讨论】:

  • 不确定,但你能不能只使用内置的urllib 模块并在带有thread 模块的后台线程中运行它?
  • 我想我可能不得不这样做。我只是很困惑,想验证预期的行为。
  • 当然。我只是倾向于尽可能地坚持使用内置插件以最大限度地提高便携性。

标签: python python-requests gevent grequests


【解决方案1】:

.map() 旨在并行运行多个 URL 的检索,并且确实会等待这些任务完成(调用gevent.joinall(jobs))。

使用.send() 代替生成作业,使用Pool instance

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() 调用。

【讨论】:

  • @martijn pieters 你能提供一个带帖子的样本吗?无法通过邮寄电话使用它
  • @Avinash:改用grequests.post()?就grequests而言,各种请求方式没有区别。
  • .pool() 实际上做了什么?我没看懂文档。
【解决方案2】:

创建一个请求列表,然后使用.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)
  • sessionrequests.Session() 对象(可选)
  • size=5 同时发送 5 个请求:一旦完成其中一个请求,就会发送下一个请求
  • 在这个例子中,当任何请求(无序)完成时,它的 url 就会被打印出来

【讨论】:

    【解决方案3】:

    如果您不想使用grequests,您可以使用标准库中的requests + threading 模块通过回调实现请求。这实际上非常简单,如果您只想发送带有回调的请求,那么 API 比 grequests 提供的更好。

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-19
      • 1970-01-01
      • 2019-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-31
      • 1970-01-01
      相关资源
      最近更新 更多