pythonでのスレッドの使用
PythonはGIL(global Interpretor Lock)とキューモデルでリソースのプリエンプト問題を処理し、Python解釈器はスレッドセキュリティではなく、このロックを持ってこそpythonオブジェクトに安全にアクセスできるため、pythonはマルチCPUリソースをうまく利用できない.
前の文章ではプロセスについて話しましたが、なぜマルチスレッドが必要なのか、プロセスのオーバーヘッドが大きく、通信が面倒なため、マルチスレッドが必要で、マルチスレッドは単独のプロセスで同時に実行されるタスクです.
スレッドステータス:スリープ停止の実行準備完了
threadモジュール
start_の使用new_thread(func,(args1,args2...))
start_new_threadこのメソッドは、パラメータとして関数を受信し、スレッドを開始します.threadモジュールの使用はもうお勧めしません.
threadingモジュール
メソッドを使用してthreadingを継承Threadはrunを書き換える
一般的な方法:
start run join setDaemon isDaemon startとrunの違いに注意
join注意2点: timeoutを設定しないと、joinはスレッドが終了するまでブロックされます. スレッドは自分の実行コードでjoinできません.そうしないと がデッドロックします.
threading.local()
異なるスレッドに異なる値として保存されます.Javaのthreadlocalと
スレッド同期
りんかいしげん
臨界リソースは、実際にはマルチスレッドにアクセスされるコードです.臨界リソースへのアクセスについては、マルチスレッドが臨界リソースにアクセスすると、予想外の結果が得られます.たとえば、カウンタのincreaseメソッドでは、+1を1回呼び出し、100スレッドが呼び出されると、最終結果は通常100未満になります.これは、同時アクセスと変更によるものです.
threadロック機構
threadを使用allocate_lock()はロックを割り当て、acquireはロックを取得し、実行が完了するとreleaseが解放され、コードは以下の通りです.
条件変数ロックメカニズムは同期問題を解決できるが,複雑なマルチスレッド問題に遭遇するとどうしようもない.例えば、一般的な生産者-消費者の問題では、スレッド間で相互に感知する必要があります.ここでは条件変数を使用します.
もちろん,条件変数を用いてもロック機能が実現され,acquireとreleaseメソッドが提供され,notify notifyall waitも提供される.
生産者と消費者の例
同期キュー
Queue.Queue(maxsize=10)
sizeを1未満に設定するとsizeに制限はありません.
メソッドはput()
get()
blockパラメータがあり、デフォルト1で、空のときに取るか、満のときに保存すると待ちます.0の場合はエラーとなります
前の文章ではプロセスについて話しましたが、なぜマルチスレッドが必要なのか、プロセスのオーバーヘッドが大きく、通信が面倒なため、マルチスレッドが必要で、マルチスレッドは単独のプロセスで同時に実行されるタスクです.
スレッドステータス:スリープ停止の実行準備完了
threadモジュール
start_の使用new_thread(func,(args1,args2...))
start_new_threadこのメソッドは、パラメータとして関数を受信し、スレッドを開始します.threadモジュールの使用はもうお勧めしません.
threadingモジュール
メソッドを使用してthreadingを継承Threadはrunを書き換える
import threading,time
class ThreadDemo(threading.Thread):
def __init__(self,index,create_time):
threading.Thread.__init__(self)
self.index = index
self.create_time = create_time
def run(self):
time.sleep(1)
print (time.time()-self.create_time),"\t",self.index
print "Thread %d exit" % (self.index)
for x in range(5):
t = ThreadDemo(x,time.time())
t.start()
一般的な方法:
start run join setDaemon isDaemon startとrunの違いに注意
join注意2点:
threading.local()
異なるスレッドに異なる値として保存されます.Javaのthreadlocalと
import threading,time,random
class ThreadLocal(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.local = threading.local()
def run(self):
time.sleep(random.random())
self.local.numbers = []
for i in range(10):
self.local.numbers.append(random.choice(range(10)))
print threading.currentThread,self.local.numbers
for x in range(5):
t = ThreadLocal()
t.start()
スレッド同期
りんかいしげん
臨界リソースは、実際にはマルチスレッドにアクセスされるコードです.臨界リソースへのアクセスについては、マルチスレッドが臨界リソースにアクセスすると、予想外の結果が得られます.たとえば、カウンタのincreaseメソッドでは、+1を1回呼び出し、100スレッドが呼び出されると、最終結果は通常100未満になります.これは、同時アクセスと変更によるものです.
import threading
class Counter:
def __init__(self):
self.value = 0
def increase(self):
self.value += 1
return self.value
counter = Counter()
class ThreadDemo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print counter.increase()
for x in range(100):
t = ThreadDemo()
t.start()
の結果はほとんど100未満であり、このような問題を回避するためにいくつかの措置が必要である.threadロック機構
threadを使用allocate_lock()はロックを割り当て、acquireはロックを取得し、実行が完了するとreleaseが解放され、コードは以下の通りです.
import threading,thread
class Counter:
def __init__(self):
self.value = 0
self.lock = thread.allocate_lock()
def increase(self):
self.lock.acquire()
self.value += 1
self.lock.release()
return self.value
counter = Counter()
class ThreadDemo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print counter.increase()
for x in range(100):
t = ThreadDemo()
t.start()
条件変数ロックメカニズムは同期問題を解決できるが,複雑なマルチスレッド問題に遭遇するとどうしようもない.例えば、一般的な生産者-消費者の問題では、スレッド間で相互に感知する必要があります.ここでは条件変数を使用します.
もちろん,条件変数を用いてもロック機能が実現され,acquireとreleaseメソッドが提供され,notify notifyall waitも提供される.
生産者と消費者の例
from threading import Thread,Condition,currentThread
import time,random
class Producer(Thread):
def __init__(self,condition,goods):
Thread.__init__(self)
self.cond=condition
self.goods=goods
def run(self):
while 1:
self.cond.acquire()
self.goods.append(chr(random.randint(97, 122)))
print self.goods
cond.notifyAll()
cond.release()
time.sleep(random.choice(range(3)))
class Consumer(Thread):
def __init__(self,condition,goods):
Thread.__init__(self)
self.cond=condition
self.goods=goods
def run(self):
while 1:
cond.acquire()
while not goods:
print "has no good,wait..."
cond.wait()
print "consume:",goods.pop(0)
print self.goods
cond.release()
time.sleep(random.choice(range(2)))
goods=[]
cond=Condition()
p = Producer(cond,goods)
c = Consumer(cond,goods)
p.start()
c.start()
ここでは池に上限がないと仮定し、生産者はずっと生産することができ、消費者は池に何かがあってこそ消費することができ、暇な時にwaitを待たなければならない.ここはJAVAと同じ考え方で、違いは自分で同期の池を書く必要はありません.どうせロックはグローバルロックです.同期キュー
Queue.Queue(maxsize=10)
sizeを1未満に設定するとsizeに制限はありません.
メソッドはput()
get()
blockパラメータがあり、デフォルト1で、空のときに取るか、満のときに保存すると待ちます.0の場合はエラーとなります
# queue_example.py
from Queue import Queue
import threading
import random
import time
# Producer thread
class Producer(threading.Thread):
def __init__(self, threadname, queue):
threading.Thread.__init__(self, name = threadname)
self.sharedata = queue
def run(self):
for i in range(20):
print self.getName(),'adding',i,'to queue'
self.sharedata.put(i)
time.sleep(random.randrange(2))
print self.getName(),'Finished'
# Consumer thread
class Consumer(threading.Thread):
def __init__(self, threadname, queue):
threading.Thread.__init__(self, name = threadname)
self.sharedata = queue
def run(self):
for i in range(20):
print self.getName(),'got a value:',self.sharedata.get()
time.sleep(random.randrange(4))
print self.getName(),'Finished'
# Main thread
def main():
queue = Queue(2)
producer = Producer('Producer', queue)
consumer = Consumer('Consumer', queue)
print 'Starting threads ...'
producer.start()
consumer.start()
producer.join()
consumer.join()
print 'All threads have terminated.'
if __name__ == '__main__':
main()