Ответ 1
Извините Кеннет Рейц. Его библиотека прекрасна.
Я глуп. Мне нужно выбрать патч обезьяны для httplib следующим образом:
gevent.monkey.patch_all(httplib=True)
Поскольку исправление для httplib по умолчанию отключено.
для этого кода:
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
в sniffer он выглядит так:
описание: первые 5 запросов отсылаются библиотекой запросов, следующие 5 запросов отправляются библиотекой urllib2.
красный - это время, когда работа замерзала, темная - при получении данных... wtf?!
Как это возможно, если библиотека сокетов пропатчена, а библиотеки должны работать одинаково? Как использовать запросы без request.async для асинхронной работы?
Извините Кеннет Рейц. Его библиотека прекрасна.
Я глуп. Мне нужно выбрать патч обезьяны для httplib следующим образом:
gevent.monkey.patch_all(httplib=True)
Поскольку исправление для httplib по умолчанию отключено.
Как заметил Кеннет, еще одна вещь, которую мы можем сделать, это позволить модулю 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
Запросы поддерживают gevent, интегрированные в кодовую базу:
http://docs.python-requests.org/en/latest/user/advanced/#asynchronous-requests
Я запустил ваш код на своей машине (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
Из запросов doc Блокировка или неблокирование:
Если вас беспокоит использование блокировки ввода-вывода, есть много проектов, которые объединяют запросы с одной из инфраструктур асинхронности Python. Два отличных примера: grequests и requests-futures.