Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

python - requests не работает асинхронно

80K
01 марта 2012 года
alexey-grom
1 / / 01.03.2012
Наблюдается очень странное поведение библиотеки requests при попытке работать с ней асинхронно с помощью библиотек gevent или eventlet.
Этот код:

Код:
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 запросов отправлена асинхронно с помощью requests, вторая группа - с помощью urllib2.
Красным на диаграмме обозначено время когда сокеты "висели" и из них не читали данные. Темным - когда производилось чтение.
Из диаграммы видно, что чтение из сокетов при использовании requests происходит строго последовательно, а с urllib2 - параллельно, т.е. асинхронно.

Как такое может быть если socket.recv пропатчен (gevent.monkey) и используется обеими библиотеками?
Что вообще нужно сделать чтобы requests заработал как нужно, т.е. асинхронно?


UPD: urllib2+cookielib предлагать не нужно - весь код придется переписывать на них, не говоря уже о том, что они не слишком-то удобны по сравнению с requests. И кстати, в requests, например, отказались от urllib2 в пользу urllib3, который имеет connectionpool, написанный нашим соотечественником.

UPD2: requests.asynс тоже не вариант, потому что там ничего принципиального кроме пула gevent и настоятельной рекомендации использовать requests.asynс.map для ожидания этого пула.

UPD3: на stackoverflow.com на этот вопрос ответил сам автор requests, но ничего кроме отсылки к документации и использованию requests.asynс не посоветовал, хотя уже и переписывали его для requests.asynс с тем же результатом. как выяснилось, этот код успешно работает в асинхронном режиме в линуксе и даже быстрее чем urllib2, но не работает на винде.

UPD4: пробовал пересобирать libevent, greenlet, gevent, но это не решило проблему.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог