python - requests не работает асинхронно
Этот код:
Код:
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)
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
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, но это не решило проблему.