web-dev-qa-db-ja.com

grequestsはどのように非同期ですか?

pythonリクエストライブラリをしばらく使用していましたが、最近リクエストを非同期的に行う必要がありました。つまり、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要求を同時に実行し、すべての応答を単一のコールバックに送信するためのものです。これは正確ですか?

38
cacois

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)
7
kylebebak

リクエストのリストを作成し、_.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つのリクエストを送信します。そのうちの1つが完了するとすぐに、次のリクエストが送信されます
  • この例では、リクエスト(順不同)が完了すると、そのURLが出力されます
0
Winand