web-dev-qa-db-ja.com

Pythonマルチスレッドでのリクエスト

私は過去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()
19
krypt

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つの優れた例は、 grequestsrequests-futures

この方法を使用すると、10個のURLで顕著なパフォーマンスの向上が得られます。0.877s vs 3.852s元のメソッドで。

28
Will