私は過去2日間、マルチスレッド機能を備えたスクレーパーを構築しようと試みてきました。どういうわけか私はまだそれを管理することができませんでした。最初は、スレッドモジュールを使用して通常のマルチスレッドアプローチを試みましたが、シングルスレッドを使用するよりも高速ではありませんでした。その後、リクエストがブロックされ、マルチスレッドのアプローチが実際に機能していないことを知りました。そこで私は調査を続け、grequestsとgeventについて知りました。現在、geventを使用してテストを実行していますが、単一のスレッドを使用するよりも高速ではありません。私のコーディングは間違っていますか?
クラスの関連部分は次のとおりです。
import gevent.monkey
from gevent.pool import Pool
import requests
gevent.monkey.patch_all()
class Test:
def __init__(self):
self.session = requests.Session()
self.pool = Pool(20)
self.urls = [...urls...]
def fetch(self, url):
try:
response = self.session.get(url, headers=self.headers)
except:
self.logger.error('Problem: ', id, exc_info=True)
self.doSomething(response)
def async(self):
for url in self.urls:
self.pool.spawn( self.fetch, url )
self.pool.join()
test = Test()
test.async()
grequests
モジュール をインストールします。これはgevent
で動作します(requests
は非同期用に設計されていません):
pip install grequests
次に、コードを次のように変更します。
import grequests
class Test:
def __init__(self):
self.urls = [
'http://www.example.com',
'http://www.google.com',
'http://www.yahoo.com',
'http://www.stackoverflow.com/',
'http://www.reddit.com/'
]
def exception(self, request, exception):
print "Problem: {}: {}".format(request.url, exception)
def async(self):
results = grequests.map((grequests.get(u) for u in self.urls), exception_handler=self.exception, size=5)
print results
test = Test()
test.async()
これは 公式に推奨requests
プロジェクトによって:
ブロッキングまたは非ブロッキング?
デフォルトのトランスポートアダプターが適切に配置されている場合、リクエストは非ブロッキングIOを提供しません。
Response.content
プロパティは、応答全体がダウンロードされるまでブロックします。さらに細かくする必要がある場合は、ライブラリのストリーミング機能( ストリーミングリクエスト を参照)を使用して、一度に少量の応答を取得できます。ただし、これらの呼び出しは引き続きブロックされます。ブロッキングIOの使用に不安がある場合は、リクエストをPythonの非同期フレームワークの1つと組み合わせるプロジェクトが数多くあります。 2つの優れた例は、
grequests
とrequests-futures
。
この方法を使用すると、10個のURLで顕著なパフォーマンスの向上が得られます。0.877s
vs 3.852s
元のメソッドで。