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を書き換える
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点:
  • timeoutを設定しないと、joinはスレッドが終了するまでブロックされます.
  • スレッドは自分の実行コードでjoinできません.そうしないと
  • がデッドロックします.
    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()