14

Pythonでマルチスレッドプログラミングを理解しようとしています。これは、シリアルとパラレルの速度を比較したい単純なタスクです。

import threading
import Queue
import time
import math

def sinFunc(offset, n):
  result = []
  for i in range(n):
    result.append(math.sin(offset + i * i))
  return result

def timeSerial(k, n):
  t1 = time.time()    
  answers = []
  for i in range(k):
    answers.append(sinFunc(i, n))
  t2 = time.time()
  print "Serial time elapsed: %f" % (t2-t1)

class Worker(threading.Thread):

  def __init__(self, queue, name):
    self.__queue = queue
    threading.Thread.__init__(self)
    self.name = name

  def process(self, item):
    offset, n = item
    self.__queue.put(sinFunc(offset, n))
    self.__queue.task_done()
    self.__queue.task_done()

  def run(self):
    while 1:
        item = self.__queue.get()
        if item is None:
            self.__queue.task_done()
            break
        self.process(item)

def timeParallel(k, n, numThreads):
  t1 = time.time()    
  queue = Queue.Queue(0)
  for i in range(k):
    queue.put((i, n))
  for i in range(numThreads):
    queue.put(None)    
  for i in range(numThreads):
    Worker(queue, i).start()
  queue.join()
  t2 = time.time()
  print "Serial time elapsed: %f" % (t2-t1)

if __name__ == '__main__':

  n = 100000
  k = 100
  numThreads = 10

  timeSerial(k, n)
  timeParallel(k, n, numThreads)

#Serial time elapsed: 2.350883
#Serial time elapsed: 2.843030

誰かが私に何が起こっているのか説明できますか? 私は C++ に慣れており、このモジュールを使用した同様のバージョンでは、期待どおりのスピードアップが見られます。

4

3 に答える 3

27

他の回答は、GILがcpythonの問題であるという問題に言及しています。でも、少し情報が足りないと感じました。これにより、スレッドで実行しているコードがCPUにバインドされている状況でパフォーマンスの問題が発生します。ここでのあなたの場合、はい、スレッドで多くの計算を行うと、パフォーマンスが劇的に低下する可能性があります。

ただし、ネットワークアプリケーションの多くのソケットからの読み取りやサブプロセスの呼び出しなど、IOバウンドの多い処理を実行している場合は、スレッドからパフォーマンスを向上させることができます。上記のコードの簡単な例は、愚かな単純な呼び出しをシェルに追加することです。

import os

def sinFunc(offset, n):
  result = []
  for i in xrange(n):
    result.append(math.sin(offset + i * i))
  os.system("echo 'could be a database query' >> /dev/null; sleep .1")
  return result

その呼び出しは、ファイルシステムで待機しているようなものだった可能性があります。ただし、この例では、スレッドがIOを待機しているときにGILを解放でき、他のスレッドが処理を続行するため、スレッド化が有益であることがわかります。それでも、スレッドの作成と同期のオーバーヘッドによって、より多くのスレッドが無効になり始める場合のスイートスポットがまだあります。

CPUにバインドされたコードの場合、マルチプロセッシングを利用します

記事から:http://www.informit.com/articles/article.aspx?p = 1850445&seqNum = 9

...スレッド化はI/Oバウンドアプリケーションに適しています(I / OはGILを解放し、より多くの同時実行性を可能にします)...

スレッドとプロセスに関する同様の質問参照:https:
//stackoverflow.com/a/1227204/496445
https://stackoverflow.com/a/990436/496445

于 2012-05-28T19:17:55.707 に答える
6

Python には深刻なスレッドの問題があります。基本的に、Python アプリケーションにスレッドを追加しても、ほとんどの場合は高速化に失敗し、場合によっては低速化します。

これはGlobal Interpreter Lockまたは GIL によるものです。

これは、このテーマに関する講演を含むブログ投稿です。

この制限を回避する 1 つの方法は、スレッドの代わりにプロセスを使用することです。これはmultiprocessingモジュールによって簡単になります。

于 2012-05-28T18:39:52.107 に答える
0

C で記述された Python ライブラリは、Global Interpreter Lock (GIL) を自由に取得/解放できます。Python オブジェクトを使用しないものは GIL を解放して、他のスレッドが参照できるようにすることができますが、数学ライブラリは常に Python オブジェクトを使用しているため、math.sin は効果的にシリアル化されていると思います。ロック/ロック解除はオーバーヘッドであるため、Python スレッドがプロセスよりも遅くなることは珍しくありません。

于 2012-05-28T18:48:02.860 に答える