3

数時間前、私は Python のマルチスレッドについて質問しました。それがどのように機能するかを理解するために、いくつかの実験を行いました。ここに私のテストがあります:


スレッドを使用する Python スクリプト:

import threading
import Queue
import time

s = 0;

class ThreadClass(threading.Thread):

    lck = threading.Lock()

    def __init__(self, inQ, outQ):
        threading.Thread.__init__(self)
        self.inQ = inQ
        self.outQ = outQ

    def run(self):
        while True:
            global s
            #print self.getName()+" is running..."
            self.item = self.inQ.get()
            #self.inQ.task_done()
            ThreadClass.lck.acquire()
            s += self.item
            ThreadClass.lck.release()
            #self.inQ.task_done()
            self.outQ.put(self.item)
            self.inQ.task_done()

inQ = Queue.Queue()
outQ = Queue.Queue()

i = 0
n = 1000000

print "putting items to input"
while i<n:
    inQ.put(i)
    i += 1

start_time = time.time()
print "starting threads..."
for i in xrange(10):
    t = ThreadClass(inQ, outQ);
    t.setDaemon(True)
    t.start()


inQ.join()
end_time = time.time()
print "Elapsed time is: %s"%(end_time - start_time)
print s

以下は、単純な while ループを使用した同じ機能を備えています。

import Queue
import time

inQ = Queue.Queue()
outQ = Queue.Queue()

i = 0
n = 1000000
sum = 0

print "putting items to input"
while i<n:
    inQ.put(i)
    i += 1

print "while loop starts..."
start_time = time.time()
while inQ.qsize() > 0:
    item = inQ.get()
    sum += item
    outQ.put(item)
end_time = time.time()

print "Elapsed time is: %s"%(end_time - start_time)
print sum

これらのプログラムを自分のマシンで実行すると、スレッドが単純な while ループよりもはるかに遅いことがわかります。スレッドについて少し混乱していて、スレッド化されたコードの何が問題なのか知りたいです。どうすれば (この状況で) 最適化できますか? また、while ループより遅いのはなぜですか?

4

1 に答える 1

2

スレッド化は常にトリッキーです。Python でのスレッド化は特別です。

最適化について議論するには、特別なケースに焦点を当てる必要があります。そうでなければ、単一の答えはありません。私のコンピューターの初期スレッド ソリューションは 37.11 秒で実行されます。ローカル変数を使用して各スレッドの要素を合計し、最後にのみロックすると、時間は 32.62 秒に低下します。

Ok。スレッドなしのソリューションは 7.47 秒で実行されます。偉大な。しかし、Python で大量の数値を合計したい場合は、組み込み関数 sum を使用するだけです。したがって、スレッドがなく、合計が組み込まれた List を使用すると、時間は 0.09 秒に低下します。すごい!

なんで?

Python のスレッドは、Global Interpreter Lock (GIL) の対象です。Python コードを並行して実行することはありません。それらは実際のスレッドですが、内部的には、GIL を別のスレッドに解放する前に X Python 命令を実行することしか許可されていません。非常に単純な計算の場合、スレッドの作成、ロック、およびコンテキストの切り替えのコストは、単純な計算のコストよりもはるかに大きくなります。したがって、この場合、オーバーヘッドは計算自体の 5 倍になります。Python でのスレッド化は、非同期 I/O を使用できない場合、または同時に実行する必要があるブロック関数がある場合に興味深いものです。

しかし、組み込みの合計が Python のスレッドなしソリューションよりも速いのはなぜですか? 組み込みの sum は C で実装されており、Python のループはパフォーマンスが低下します。したがって、組み込みの合計を使用してリストのすべての要素を反復する方がはるかに高速です。

いつもそうですか?いいえ、それはあなたが何をしているかによります。これらの数値を n 個の異なるファイルに書き込んでいた場合、I/O 中に GIL が解放されるため、スレッド ソリューションにチャンスがある可能性があります。しかし、それでも、I/O バッファリング/ディスク同期時間がゲームチェンジャーではないかどうかを確認する必要があります. この種の詳細は、最終的な回答を非常に困難にします。したがって、何かを最適化したい場合は、最適化する必要があるものを正確に把握する必要があります。Python で数値のリストを合計するには、組み込みの sum を使用します。

于 2012-09-19T13:36:10.263 に答える