как включить асинхронный режим запросов?

для этого кода:

import sys

import gevent
from gevent import monkey

monkey.patch_all()

import requests
import urllib2

def worker(url, use_urllib2=False):
    if use_urllib2:
        content = urllib2.urlopen(url).read().lower()
    else:
        content = requests.get(url, prefetch=True).content.lower()
    title = content.split('<title>')[1].split('</title>')[0].strip()

urls = ['http://www.mail.ru']*5

def by_requests():
    jobs = [gevent.spawn(worker, url) for url in urls]
    gevent.joinall(jobs)

def by_urllib2():
    jobs = [gevent.spawn(worker, url, True) for url in urls]
    gevent.joinall(jobs)

if __name__=='__main__':
    from timeit import Timer
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests")  
    print 'by requests: %s seconds'%t.timeit(number=3)
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2")  
    print 'by urllib2: %s seconds'%t.timeit(number=3)
    sys.exit(0)

этот результат:

by requests: 18.3397213892 seconds
by urllib2: 2.48605842363 seconds

в сниффере это выглядит так:

описание: первые 5 запросов отправляются библиотекой запросов, следующие 5 запросов отправляются библиотекой urllib2. красный - время, когда работа зависла, темный - время приема данных... wtf?!

Как это возможно, если библиотека сокетов исправлена ​​и библиотеки должны работать одинаково? Как использовать запросы без request.async для асинхронной работы?


person user12397901    schedule 29.02.2012    source источник
comment
Можете ли вы объяснить свою проблему немного подробнее? Почему вы не хотите использовать модуль request.async?   -  person Phani    schedule 01.03.2012
comment
Запросы не работают асинхронно. Почему? Я не хочу использовать request.async, потому что он содержит плохой интерфейс для использования и не работает асинхронно. Посмотрите на картинку, там видно как работают запросы и urllib2.   -  person user12397901    schedule 01.03.2012
comment
См. stackoverflow.com/questions/9110593/. и github.com/kennethreitz/grequests.   -  person Piotr Migdal    schedule 08.02.2013


Ответы (5)


Прости, Кеннет Рейц. Его библиотека прекрасна.

Я глупый. Мне нужно выбрать патч для обезьяны для httplib следующим образом:

gevent.monkey.patch_all(httplib=True)

Потому что патч для httplib по умолчанию отключен.

person user12397901    schedule 05.03.2012
comment
Больше недействительно: ValueError: gevent.httplib больше не предоставляется, httplib должно быть False - person mamcx; 01.03.2013
comment
Используйте grequests (от @KennethReitz). В основном он переопределяет основные глаголы и наследует остальные. - person Dustin Oprea; 27.09.2014

Как было указано Кеннетом, мы можем также позволить модулю requests обрабатывать асинхронную часть. Я внес соответствующие изменения в ваш код. Опять же, для меня результаты неизменно показывают, что модуль requests работает лучше, чем urllib2.

Это означает, что мы не можем "нанизать" часть обратного вызова. Но это должно быть хорошо, потому что основной выигрыш следует ожидать только с HTTP-запросами из-за задержки запроса/ответа.

import sys

import gevent
from gevent import monkey

monkey.patch_all()

import requests
from requests import async
import urllib2

def call_back(resp):
    content = resp.content
    title = content.split('<title>')[1].split('</title>')[0].strip()
    return title

def worker(url, use_urllib2=False):
    if use_urllib2:
        content = urllib2.urlopen(url).read().lower()
        title = content.split('<title>')[1].split('</title>')[0].strip()

    else:
        rs = [async.get(u) for u in url]
        resps = async.map(rs)
        for resp in resps:
            call_back(resp) 

urls = ['http://www.mail.ru']*5

def by_requests():
    worker(urls)
def by_urllib2():
    jobs = [gevent.spawn(worker, url, True) for url in urls]
    gevent.joinall(jobs)

if __name__=='__main__':
    from timeit import Timer
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests")
    print 'by requests: %s seconds'%t.timeit(number=3)
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2")
    print 'by urllib2: %s seconds'%t.timeit(number=3)
    sys.exit(0)

Вот один из моих результатов:

by requests: 2.44117593765 seconds
by urllib2: 4.41298294067 seconds
person Phani    schedule 01.03.2012
comment
Привет! Спасибо за интерес к моей проблеме. Я выполнил ваш код и обновил изображение первого поста, чтобы показать, как работает ваш код. - person user12397901; 02.03.2012
comment
Это результаты работы: по запросам: 25,532893147 секунд по urllib2: 9,65230888283 секунд - person user12397901; 02.03.2012
comment
Боюсь, я не могу воспроизвести вашу проблему. Я обновил gevent до 0.13.6 и попробовал его на двух разных машинах. Но модуль requests работал асинхронно. К вашему сведению, я пробовал это на Ubuntu 11.04 и 11.10. - person Phani; 02.03.2012
comment
Я тестирую код на другой машине с Linux, и он работает асинхронно. Я понял, что проблема в сборке gevent для Windows, и я успешно попытался перестроить библиотеки gevent и greenlet, но это не помогло. Я не знаю, что делать дальше. - person user12397901; 03.03.2012

Запросы имеют поддержку gevent, интегрированную в кодовую базу:

http://docs.python-requests.org/en/latest/user/advanced/#asynchronous-requests

person Kenneth Reitz    schedule 01.03.2012
comment
Извините, но это тоже не асинхронно работает. Почему это возможно? - person user12397901; 02.03.2012
comment
Большое спасибо за проявленный интерес к моей проблеме. Для меня большая честь, что автор этой библиотеки ответил на мой вопрос. - person user12397901; 02.03.2012
comment
Извините, этой страницы еще не существует - person Mooncrater; 02.03.2020

Я запустил ваш код на своей машине (python 2.7.1, gevent 0.13.0, requests 0.10.6). Оказалось, что время всегда было на добрую секунду или две быстрее при использовании модуля запросов. Какие версии вы используете? Обновление может просто решить проблему для вас.

by requests: 3.7847161293 seconds
by urllib2: 4.92611193657 seconds

by requests: 2.90777993202 seconds
by urllib2: 7.99798607826 seconds
person Phani    schedule 01.03.2012
comment
Я использую следующие версии: python 2.7.2.5, gevent 0.13.6, запросы 0.10.6. - person user12397901; 02.03.2012
comment
Ваши версии еще более продвинуты, так что это действительно странно. Я опубликовал еще один ответ, который может вам помочь. - person Phani; 02.03.2012