このコードの場合:
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?!
ソケットライブラリにパッチを適用し、ライブラリが同じように機能する必要がある場合、どのように可能ですか?非同期作業のためにrequests.asyncなしでリクエストを使用するにはどうすればよいですか?
申し訳ありませんがケネス・レイツ。彼の図書館は素晴らしいです。
私は愚かだ。次のようにhttplibのモンキーパッチを選択する必要があります。
gevent.monkey.patch_all(httplib=True)
Httplibのパッチはデフォルトで無効になっているためです。
Kennethが指摘したように、私たちにできるもう1つのことは、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)
これが私の結果の1つです:
by requests: 2.44117593765 seconds
by urllib2: 4.41298294067 seconds
Requestsには、コードベースに統合されたgeventサポートがあります。
http://docs.python-requests.org/en/latest/user/advanced/#asynchronous-requests
私は自分のマシンであなたのコードを実行しました(python 2.7.1
、gevent 0.13.0
、requests 0.10.6
)。リクエストモジュールを使用すると、時間は常に1〜2秒速くなることがわかりました。どのバージョンを使用していますか?アップグレードするだけで問題が解決する場合があります。
by requests: 3.7847161293 seconds
by urllib2: 4.92611193657 seconds
by requests: 2.90777993202 seconds
by urllib2: 7.99798607826 seconds
リクエストドキュメントから ブロッキングまたは非ブロッキング :
ブロッキングIOの使用について懸念がある場合は、リクエストをPythonの非同期フレームワークの1つと組み合わせるプロジェクトがたくさんあります。 2つの優れた例は grequests と requests-futures です。