2011-09-09 6 views
4

URLを複数回取得する必要がある小さなクローラを作成しています。すべてのスレッドを同時に(同時に)実行します。同時に複数のスレッドをPythonで実行することは可能ですか?

私はこれを行うコードを少し書いています。それはスレッドが同時に実行されているように、要求の間にほとんど隙間があります思われませんApacheのログから

import thread 
from urllib2 import Request, urlopen, URLError, HTTPError 


def getPAGE(FetchAddress): 
    attempts = 0 
    while attempts < 2: 
     req = Request(FetchAddress, None) 
     try: 
      response = urlopen(req, timeout = 8) #fetching the url 
      print "fetched url %s" % FetchAddress 
     except HTTPError, e: 
      print 'The server didn\'t do the request.' 
      print 'Error code: ', str(e.code) + " address: " + FetchAddress 
      time.sleep(4) 
      attempts += 1 
     except URLError, e: 
      print 'Failed to reach the server.' 
      print 'Reason: ', str(e.reason) + " address: " + FetchAddress 
      time.sleep(4) 
      attempts += 1 
     except Exception, e: 
      print 'Something bad happened in gatPAGE.' 
      print 'Reason: ', str(e.reason) + " address: " + FetchAddress 
      time.sleep(4) 
      attempts += 1 
     else: 
      try: 
       return response.read() 
      except: 
       "there was an error with response.read()" 
       return None 
    return None 

url = ("http://www.domain.com",) 

for i in range(1,50): 
    thread.start_new_thread(getPAGE, url) 

、それはほとんど検出できないのですが、私は、スレッドが実際に平行でないことがわかります。

私はGILについて読んだことがありますが、C \ C++コードを呼び出してバイパスする方法はありますか? GILでスレッディングがどのように可能か分かりませんか? Pythonは基本的に、前のスレッドで終了するとすぐに次のスレッドを解釈しますか?

ありがとうございました。

+0

並列で実行されますが、ブロックをurlopenないだろう、それはスレッドが並列にダウンロードすることを意味しますか?サーバーを所有して試してみて、サーバー側に人為的な遅延を3秒間導入してから、スレッドが並列して開始し終了するかどうかを確認する必要があります –

答えて

4

GILは、しばしばPythonスレッドが並行して実行されないようにします。

ただし、必ずしもそうとは限りません。 1つの例外はI/Oバウンドコードです。スレッドがI/O要求を完了するのを待っているとき、スレッドは通常、待機に入る前にGILを解放していました。これは、その間に他のスレッドが進捗することを意味します。一般的に

は、しかし、multiprocessingは真の並列処理が必要とされる安全な賭けです。

0

また、これは現時点ではすべてのちょうど研究や知的冷罵ですが、それは大きな何かに成長する可能性があり(これGILを離れてやって)私たちはソフトウェアの移行メモリを持っていますpypyの将来のようなものを見ることができます。

1

私はGILについて読んだことがありますが、C \ C++コードを呼び出してバイパスする方法はありますか?

実際はありません。 ctypesを通して呼び出される関数は、それらの呼び出しの間、GILを解放します。ブロッキングI/Oを実行する関数もそれを解放します。他の同様の状況がありますが、それらは常に主要なPythonインタプリタループの外側にコードを含みます。 PythonコードでGILを放棄することはできません。

1

あなたは、すべてのスレッドを作成するには、このようなアプローチを使用し、それらが条件オブジェクトを待つ必要があり、その後、それらがURLをフェッチを開始している「同時に」することができます

#!/usr/bin/env python 
import threading 
import datetime 
import urllib2 

allgo = threading.Condition() 

class ThreadClass(threading.Thread): 
    def run(self): 
     allgo.acquire() 
     allgo.wait() 
     allgo.release() 
     print "%s at %s\n" % (self.getName(), datetime.datetime.now()) 
     url = urllib2.urlopen("http://www.ibm.com") 

for i in range(50): 
    t = ThreadClass() 
    t.start() 

allgo.acquire() 
allgo.notify_all() 
allgo.release() 

これはあなたになるだろう、すべてのフェッチが同時に起こるしかしを持つに近いビット:

  • お使いのコンピュータを残してネットワークパケットがないと同時に、シーケンスのイーサネットワイヤに沿って通過し、
  • マシンに16以上のコアがある場合でも、マシンとWebホストの間にあるルータ、ブリッジ、モデム、またはその他の機器がコア数が少なく、要求をシリアル化する可​​能性があります。
  • Webサーバーあなたはあなたのリクエストに応答するためにaccept()コールを使用します。正しい動作のためには、サーバーグローバルロックを使用して実装され、1つのサーバープロセス/スレッドのみがクエリに応答するようにします。たとえあなたのリクエストの一部がサーバに同時に到着したとしても、になると、これによってシリアル化が発生します。

おそらく大きい程度(いくつかの仕上げの前に開始する、すなわち他人)に重複にあなたの要求を取得しますが、あなたはあなたのすべての要求がのサーバ上で同時にを開始するために取得するつもりはありませんしています。

0

あなたは(将来的には多分PyPy)のJythonやIronPythonのを使用してコードを実行した場合、それは

関連する問題