亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

マルチスレッドプログラミング

実際には、スレッドが作成された後、スレッドは常に狀態(tài)を維持するわけではなく、その狀態(tài)は大まかに次のとおりです:

New は

Runnable Ready を作成します。スケジュールを待っています

実行中実行中

ブロックされましたブロックされました。待機(jī)ロック、スリープ狀態(tài)でブロッキングが発生する可能性があります。

デッドデス

スレッドにはさまざまな狀態(tài)とさまざまなタイプがあります。大きく分けて次のようになります。

メインスレッド

サブスレッド

デーモンスレッド(バックグラウンドスレッド)

フォアグラウンドスレッド

完全な簡(jiǎn)単な理解 この後、具體的なコードの使用法を見ていきます。

1. スレッドの作成

Python には、マルチスレッド操作用の 2 つのモジュール (スレッドとスレッド) が用意されています。

前者は相対的に低レベル モジュールは、下位レベルの操作に使用され、一般的なアプリケーション レベルの開発では一般的に使用されません。

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import time
import threading
class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            print('thread {}, @number: {}'.format(self.name, i))
            time.sleep(1)
def main():
    print("Start main threading")
    # 創(chuàng)建三個(gè)線程
    threads = [MyThread() for i in range(3)]
    # 啟動(dòng)三個(gè)線程
    for t in threads:
        t.start()
    print("End Main threading")
if __name__ == '__main__':
    main()

実行結(jié)果:

Start main threading
thread Thread-1, @number: 0
thread Thread-2, @number: 0
thread Thread-3, @number: 0
End Main threading
thread Thread-2, @number: 1
thread Thread-1, @number: 1
thread Thread-3, @number: 1
thread Thread-1, @number: 2
thread Thread-3, @number: 2
thread Thread-2, @number: 2
thread Thread-2, @number: 3
thread Thread-3, @number: 3
thread Thread-1, @number: 3
thread Thread-3, @number: 4
thread Thread-2, @number: 4
thread Thread-1, @number: 4

ここでの異なる環(huán)境の出力結(jié)果は明らかに異なることに注意してください。

2. スレッドのマージ (join メソッド)

上記の例で出力された結(jié)果から、メインスレッドが終了した後も、子スレッドはまだ実行中です。 。したがって、メインスレッドは、子スレッドの実行が終了するまで待ってから終了する必要があります。

現(xiàn)時(shí)點(diǎn)では、join メソッドを使用する必要があります。

上記の例では、次のようなコードを追加します。

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import time
import threading
class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            print('thread {}, @number: {}'.format(self.name, i))
            time.sleep(1)
def main():
    print("Start main threading")
    # 創(chuàng)建三個(gè)線程
    threads = [MyThread() for i in range(3)]
    # 啟動(dòng)三個(gè)線程
    for t in threads:
        t.start()
    # 一次讓新創(chuàng)建的線程執(zhí)行 join
    for t in threads:
        t.join()
    print("End Main threading")
if __name__ == '__main__':
    main()

出力された結(jié)果から、上記の例で出力された結(jié)果と比較して、メイン スレッドが待機(jī)中 子スレッドの実行が終了すると終了します。

Start main threading
thread Thread-1, @number: 0
thread Thread-2, @number: 0
thread Thread-3, @number: 0
thread Thread-1, @number: 1
thread Thread-3, @number: 1
thread Thread-2, @number: 1
thread Thread-2, @number: 2
thread Thread-1, @number: 2
thread Thread-3, @number: 2
thread Thread-2, @number: 3
thread Thread-1, @number: 3
thread Thread-3, @number: 3
thread Thread-3, @number: 4
thread Thread-2, @number: 4
thread Thread-1, @number: 4
End Main threading

3. スレッドの同期とミューテックス ロック

スレッドの読み込みを使用してデータを取得すると、通常、データが同期しなくなります。もちろん、この時(shí)點(diǎn)でリソースをロックできます。つまり、リソースにアクセスするスレッドは、リソースにアクセスする前にロックを取得する必要があります。

スレッド モジュールはロック機(jī)能を提供します。

lock = threading.Lock()

スレッドでロックを取得

lock.acquire()

使用が完了したら、必ずロックを解放する必要があります

lock.release()

もちろん、同じリソースに対する複數(shù)のリクエストをサポートするために同じスレッドで、Python はリエントラント ロック (RLock) を利用できます。 RLock は內(nèi)部的にロックとカウンタ変數(shù)を保持しており、カウンタは取得回?cái)?shù)を記録するため、リソースが複數(shù)回必要になる可能性があります。スレッドのすべての取得が解放されるまで、他のスレッドがリソースを取得できます。

それでは、リエントラント ロックを作成するにはどうすればよいでしょうか?これはコードの問(wèn)題でもあります:

r_lock = threading.RLock()

4. 條件條件変數(shù)

実用的なロックではスレッド同期を?qū)g現(xiàn)できますが、より複雑な環(huán)境では、いくつかの條件を?qū)g裝する必要があります。ロックの裁判官のために。 Python は Condition オブジェクトを提供します。 Condition オブジェクトは、特定のイベントがトリガーされた後、または特定の條件が満たされた後にデータを処理するために使用できます。Lock オブジェクトの取得メソッドと解放メソッドに加えて、待機(jī)メソッドと通知メソッドも提供します。スレッドは最初に條件変數(shù)ロックを取得します。條件が不十分な場(chǎng)合はスレッドは待機(jī)し、條件が満たされた場(chǎng)合はスレッドが実行され、他のスレッドに通知することもできます。待ち狀態(tài)にある他のスレッドは、通知を受け取った後に條件を再判斷します。

條件変數(shù)は、異なるスレッドが次々にロックを取得していると見なすことができ、條件が満たされない場(chǎng)合は、(Lock または RLock) 待機(jī)プールに投入されると理解できます。他のスレッドに直接通知し、狀況を再判斷してください。このプロセスは、複雑な同期問(wèn)題を解決するために継続的に繰り返されます。

35192f0e58595b25a0c422efd13ef05.png

このモデルは、生産者/消費(fèi)者モデルでよく使用されます。具體的には、オンライン ショッピングの購(gòu)入者と販売者の次の例を見てください:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import threading, time
class Consumer(threading.Thread):
    def __init__(self, cond, name):
        # 初始化
        super(Consumer, self).__init__()
        self.cond = cond
        self.name = name
    def run(self):
        # 確保先運(yùn)行Seeker中的方法
        time.sleep(1)
        self.cond.acquire()
        print(self.name + ': 我這兩件商品一起買,可以便宜點(diǎn)嗎')
        self.cond.notify()
        self.cond.wait()
        print(self.name + ': 我已經(jīng)提交訂單了,你修改下價(jià)格')
        self.cond.notify()
        self.cond.wait()
        print(self.name + ': 收到,我支付成功了')
        self.cond.notify()
        self.cond.release()
        print(self.name + ': 等待收貨')
class Producer(threading.Thread):
    def __init__(self, cond, name):
        super(Producer, self).__init__()
        self.cond = cond
        self.name = name
    def run(self):
        self.cond.acquire()
        # 釋放對(duì)瑣的占用,同時(shí)線程掛起在這里,直到被 notify 并重新占有瑣。
        self.cond.wait()
        print(self.name + ': 可以的,你提交訂單吧')
        self.cond.notify()
        self.cond.wait()
        print(self.name + ': 好了,已經(jīng)修改了')
        self.cond.notify()
        self.cond.wait()
        print(self.name + ': 嗯,收款成功,馬上給你發(fā)貨')
        self.cond.release()
        print(self.name + ': 發(fā)貨商品')
cond = threading.Condition()
consumer = Consumer(cond, '買家(兩點(diǎn)水)')
producer = Producer(cond, '賣家(三點(diǎn)水)')
consumer.start()
producer.start()

出力結(jié)果は次のとおりです:

買家(兩點(diǎn)水): 我這兩件商品一起買,可以便宜點(diǎn)嗎
賣家(三點(diǎn)水): 可以的,你提交訂單吧
買家(兩點(diǎn)水): 我已經(jīng)提交訂單了,你修改下價(jià)格
賣家(三點(diǎn)水): 好了,已經(jīng)修改了
買家(兩點(diǎn)水): 收到,我支付成功了
買家(兩點(diǎn)水): 等待收貨
賣家(三點(diǎn)水): 嗯,收款成功,馬上給你發(fā)貨
賣家(三點(diǎn)水): 發(fā)貨商品

5. スレッド間通信

プログラム內(nèi)に複數(shù)のスレッドがある場(chǎng)合、必然的にこれらのスレッドは相互に通信する必要があります。では、これらのスレッド間で情報(bào)やデータを安全に交換するにはどうすればよいでしょうか?

おそらく、あるスレッドから別のスレッドにデータを送信する最も安全な方法は、キュー ライブラリのキューを使用することです。複數(shù)のスレッドで共有される Queue オブジェクトを作成します。このオブジェクトは、put() および get() 操作を使用してキューに要素を追加または削除します。

# -*- coding: UTF-8 -*-
from queue import Queue
from threading import Thread
isRead = True
def write(q):
    # 寫數(shù)據(jù)進(jìn)程
    for value in ['兩點(diǎn)水', '三點(diǎn)水', '四點(diǎn)水']:
        print('寫進(jìn) Queue 的值為:{0}'.format(value))
        q.put(value)
def read(q):
    # 讀取數(shù)據(jù)進(jìn)程
    while isRead:
        value = q.get(True)
        print('從 Queue 讀取的值為:{0}'.format(value))
if __name__ == '__main__':
    q = Queue()
    t1 = Thread(target=write, args=(q,))
    t2 = Thread(target=read, args=(q,))
    t1.start()
    t2.start()

出力結(jié)果は次のとおりです:

寫進(jìn) Queue 的值為:兩點(diǎn)水
寫進(jìn) Queue 的值為:三點(diǎn)水
從 Queue 讀取的值為:兩點(diǎn)水
寫進(jìn) Queue 的值為:四點(diǎn)水
從 Queue 讀取的值為:三點(diǎn)水
從 Queue 讀取的值為:四點(diǎn)水

Python は、スレッド間通信用の Event オブジェクトも提供します。これは、スレッドによって設(shè)定されるシグナル フラグです。シグナル フラグが true の場(chǎng)合、他のスレッドはシグナルが接觸するまで待機(jī)します。

Event オブジェクトは単純なスレッド通信機(jī)構(gòu)を?qū)g裝しており、スレッド間の通信を?qū)g現(xiàn)するためのシグナルの設(shè)定、シグナルのクリア、待機(jī)などを提供します。

シグナルを設(shè)定します

Event の set() メソッドを使用して、Event オブジェクト內(nèi)のシグナル フラグを true に設(shè)定します。 Event オブジェクトは、內(nèi)部信號(hào)フラグのステータスを決定するための isSe() メソッドを提供します。イベント オブジェクトの set() メソッドが使用される場(chǎng)合、isSet() メソッドは true を返します。

信號(hào)をクリアします

Event オブジェクトの clear() メソッドを使用して信號(hào)をクリアしますEvent オブジェクト內(nèi)のシグナル フラグ、つまり false に設(shè)定します。Event のクリア メソッドが使用される場(chǎng)合、isSet() メソッドは false を返します。 Event オブジェクトの wait メソッドは、內(nèi)部シグナルが true の場(chǎng)合にのみ機(jī)能し、その場(chǎng)合にのみ実行され、すぐに返されます。 Event オブジェクトの內(nèi)部シグナル フラグが false の場(chǎng)合、wait メソッドは true になるまで待機(jī)してから戻ります。

例:

# -*- coding: UTF-8 -*-
import threading
class mThread(threading.Thread):
    def __init__(self, threadname):
        threading.Thread.__init__(self, name=threadname)
    def run(self):
        # 使用全局Event對(duì)象
        global event
        # 判斷Event對(duì)象內(nèi)部信號(hào)標(biāo)志
        if event.isSet():
            event.clear()
            event.wait()
            print(self.getName())
        else:
            print(self.getName())
            # 設(shè)置Event對(duì)象內(nèi)部信號(hào)標(biāo)志
            event.set()
# 生成Event對(duì)象
event = threading.Event()
# 設(shè)置Event對(duì)象內(nèi)部信號(hào)標(biāo)志
event.set()
t1 = []
for i in range(10):
    t = mThread(str(i))
    # 生成線程列表
    t1.append(t)
for i in t1:
    # 運(yùn)行線程
    i.start()

出力結(jié)果は次のとおりです:

1
0
3
2
5
4
7
6
9
8

6. バックグラウンド スレッド

デフォルトでは、メインスレッドは終了します。その後、子スレッドが參加しなくても終了します。メインスレッドが終了した後も、子スレッドは引き続き実行されます。メインスレッドを終了させたい場(chǎng)合は、そのサブスレッドも終了して実行されなくなるため、サブスレッドをバックグラウンド スレッドとして設(shè)定する必要があります。 Python には setDeamon メソッドが用意されています。

學(xué)び続ける