2013-04-15 7 views
32

Я использовал библиотеку запросов python в течение некоторого времени, и недавно мне нужно было сделать запрос асинхронно, то есть я хотел бы отправить запрос HTTP, продолжить мой основной поток и вызвать обратный вызов когда запрос возвращается.Каким образом grequests асинхронны?

Естественно, меня привели в библиотеку 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-запросов и отправки всех ответов на один обратный вызов. Это точно?

+1

Не уверен, но не могли бы вы просто использовать встроенный модуль 'urllib' и запустить его в фоновом потоке с помощью модуля' thread'? – Aya

+1

Думаю, мне, возможно, придется это сделать. Я был просто сбит с толку и хочу проверить ожидаемое поведение. – cacois

+0

Конечно. Я просто склонен придерживаться встроенных модулей, где это возможно, чтобы обеспечить максимальную мобильность. – Aya

ответ

47

.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() называет его выполняет.

+4

Ах, я понял. Это прекрасно, спасибо! – cacois

+1

@martijn pieters Можете ли вы дать образец с сообщением. Не удалось заставить его работать с почтовыми вызовами – Avinash

+0

@ Авинаш: просто используйте 'grequests.post() 'вместо этого? Что касается 'grequests', то нет никакой разницы между различными методами запросов. –

1

Создать список запросов, а затем отправить их с .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-адрес печатается
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() 

Вы можете убедиться, что он работает как AJAX звонков в JS: вы отправляете запрос на другую нить, сделать некоторые вещи на главном потоке, а когда запрос возвращает вызов функции обратного вызова. Этот обратный вызов просто печатает содержимое ответа.

async_request('get', 'http://httpbin.org/anything', callback=lambda r: print(r.json())) 
for i in range(10): 
    print(i) 
Смежные вопросы