2016-07-09 14 views
13

私は過去2日間マルチスレッド機能を備えたスクレーパーを構築しようとしていました。どういうわけか私はまだそれを管理することができませんでした。最初はスレッディングモジュールで通常のマルチスレッドアプローチを試みましたが、シングルスレッドを使用するよりも速くはありませんでした。後でリクエストがブロックされ、マルチスレッドアプローチが実際には機能していないことがわかりました。だから、私は研究を続けて、グレクエストとgeventについて知っていました。現在、私はgeventでテストを実行していますが、1つのスレッドを使用するよりも速くはありません。私のコーディングは間違っている?ここでマルチスレッドでのPythonリクエスト

は私のクラスの関連する部分である:

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() 
+0

あなたの輸入品はどこですか?また、 'multiprocessing'モジュールを試しましたか? – Will

+0

私はインポートを追加しました。申し訳ありませんが、私はそれが必要ではないと思いました。私はマルチプロセッシングを試していないが、なぜ動作しないのだろうか? – krypt

+0

問題ありません! 'gevent.monkey.patch_all()'を 'gevent.monkey.patch_all(httplib = True)'に変更してみてください。それが役に立ったら、私はそれを説明します。 – Will

答えて

17

は(requestsが非同期のために設計されていません)geventで動作grequests moduleをインストールします。

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() 

これは0123ですrequestsプロジェクトによって:あなたのオリジナルの方法で0.877s3.852s:このメソッドを使用して

Blocking Or Non-Blocking?

With the default Transport Adapter in place, Requests does not provide any kind of non-blocking IO. The Response.content property will block until the entire response has been downloaded. If you require more granularity, the streaming features of the library (see Streaming Requests) allow you to retrieve smaller quantities of the response at a time. However, these calls will still block.

If you are concerned about the use of blocking IO, there are lots of projects out there that combine Requests with one of Python's asynchronicity frameworks. Two excellent examples are grequests and requests-futures .

は私の10件のURLで顕著なパフォーマンスの向上を提供します。

+0

私のテスト環境では、同じドメインの88個のURLにリクエストを送信しています。 1つのプロセスを使用する場合、完了までに約60秒かかります。 geventを使用してもまだ60秒です。残念ながら、grequestsを使用すると、それは約60秒です。 10秒間に0.8秒よりもずっと遅い。これはターゲットサーバの制限によって引き起こされる可能性がありますか? – krypt

+0

それは完全に可能です。元の投稿の下の編集で新しい「grequests」コードを表示できますか? 'ab -c 10 -n 100 '(ApacheBench)を使ってサーバをテストしてください。私のテストURLは、すべて主要かつ効率的なサイトでした。並行要求の量を制限するために、 'size = 5'または' size = 10'を 'map()'に追加することもできます。これにより、パフォーマンスが向上する可能性があります。 – Will

+0

私は、「サイズ」の数が少ないほどパフォーマンスが向上していることに気付きました。 – Will

関連する問題