ホームページ >バックエンド開発 >Python チュートリアル >スレッド間のリソース共有と、Python マルチスレッドで一般的に使用されるロック メカニズムの概要

スレッド間のリソース共有と、Python マルチスレッドで一般的に使用されるロック メカニズムの概要

不言
不言転載
2018-10-26 17:18:592905ブラウズ

この記事では、Python マルチスレッドのスレッド間でリソース共有と一般的に使用されるロック メカニズムについて紹介します。これには一定の参考値があります。必要な友人は参照できます。お役に立てば幸いです。

#この記事では、スレッド間のリソース共有と、マルチスレッド プログラミングで一般的に使用されるロック メカニズムについて簡単に紹介します。

マルチスレッド プログラミングでは、スレッド間のリソース共有が頻繁に行われます。一般的に使用されるリソース共有方法は次のとおりです:

  • グローバル変数 (グローバル)

  • queue(キューインポートキューから)

一般的に使用されるリソース共有ロックメカニズム:

  • Lock

  • Rロック

  • セムフォア

  • 状態

( 1) スレッド間のリソース共有

  1. グローバル変数を使用することでスレッド間のリソース共有を実現できます。キーワード グローバル

コードデモ:

from threading import Thread, Lock
lock = Lock()
total = 0

'''如果不使用lock那么,最后得到的数字不一定为0;同时loack不支持连续多次acquire,如果这样做了的后果是死锁!'''
def add():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total += 1
        lock.release()
    
def sub():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
    
thread1 = Thread(target=add)
thread2 = Thread(target=sub)


# 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束
# thread1.setDaemon(True)
# thread1.setDaemon(True)

# 启动线程
thread1.start()
thread2.start()

# 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。
thread1.join()
thread2.join()

total

  1. キューを使用してリソースを共有します。キューはスレッドセーフです。

  2. from threading import Thread, Lock
    from queue import Queue
    
    def add(q):
        if q.not_full:
            q.put(1)
        
    def sub(q):
        if q.not_empty:
            recv = q.get()
            print(recv)
            q.task_done()
            
    if __name__ =='__main__':
        # 设置q最多接收3个任务,Queue是线程安全的,所以不需要Lock
        qu = Queue(3)
        thread1 = Thread(target=add, args=(qu,))
        thread2 = Thread(target=sub, args=(qu,))
        thread1.start()
        thread2.start()
        # q队列堵塞,等待所有任务都被处理完。
        qu.join()
(2) ロック(ロック/Rロック/条件/セムフォア)

  1. ロック

#Lock は継続的にロックを取得できないため、デッドロックが発生し、Lock リソースの競合によりデッドロックが発生する可能性があります。

ロックするとパフォーマンスが低下します。

from threading import Thread, Lock
lock = Lock()
total = 0

'''如果不使用lock那么,最后得到的数字不一定为0;同时lock不支持连续多次acquire,如果这样做了的后果是死锁!'''
def add():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total += 1
        lock.release()
    
def sub():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
    
thread1 = Thread(target=add)
thread2 = Thread(target=sub)

# 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束
# thread1.setDaemon(True)
# thread1.setDaemon(True)

# 启动线程
thread1.start()
thread2.start()

# 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。
thread1.join()
thread2.join()
total

  1. RLock

RLock は継続的にロックを取得できますが、ロックを解放するには対応する数の解放が必要です

連続的に取得できるため Lock なので関数内で lock 付き関数を呼び出します

from threading import Thread, Lock, RLock
lock = RLock()
total = 0
def add():
    global lock
    global total
    # RLock实现连续获取锁,但是需要相应数量的release来释放资源
    for i in range(1000000):
        lock.acquire()
        lock.acquire()
        total += 1
        lock.release()
        lock.release()
def sub():
    global lock
    global total
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
thread1 = Thread(target=add)
thread2 = Thread(target=sub)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
total

  1. 条件条件変数

条件条件変数に従いますコンテキスト管理プロトコル: ステートメントで使用すると、それを囲んでいるブロックの間、関連するロックが取得されます。

wait() メソッドはロックを解放し、別のスレッドが Notice() または Notify_all() を呼び出してウェイクアップするまでブロックします。起動されると、wait() はロックを再取得して戻ります。タイムアウトも指定できます。

最初に wait 関数を開始してシグナルを受信し、次に通知関数を開始してシグナルを送信します。

from threading import Thread, Condition
'''聊天
    Peaple1 : How are you?
    Peaple2 : I`m fine, thank you!
    
    Peaple1 : What`s your job?
    Peaple2 : My job is teacher.
    
'''

def Peaple1(condition):
    with condition:
        print('Peaple1 : ', 'How are you?')
        condition.notify()
        condition.wait()
        
        print('Peaple1 : ', 'What`s your job?')
        condition.notify()
        condition.wait()

def Peaple2(condition):
    with condition:
        condition.wait()
        print('Peaple2 : ', 'I`m fine, thank you!')
        condition.notify()
        
        condition.wait()
        print('Peaple2 : ', 'My job is teacher.')
        condition.notify()


if __name__ == '__main__':
    cond = Condition()
    thread1 = Thread(target=Peaple1, args=(cond,))
    thread2 = Thread(target=Peaple2, args=(cond,))
    
    # 此处thread2要比thread1提前启动,因为notify必须要有wait接收;如果先启动thread1,没有wait接收notify信号,那么将会死锁。
    thread2.start()
    thread1.start()

#     thread1.join()
#     thread2.join()

  1. Semphore

このクラスはセマフォ オブジェクトを実装します。セマフォは、release() 呼び出しの数からacquire() 呼び出しの数と初期値を加えた数を表すアトミック カウンタを管理します。必要に応じて、acquire() メソッドは、カウンタを負にせずに戻ることができるまでブロックします。指定しない場合、値はデフォルトの 1 になります。

#Semaphore 是用于控制进入数量的锁
#文件, 读、写, 写一般只是用于一个线程写,读可以允许有多个

import threading
import time

class HtmlSpider(threading.Thread):
    def __init__(self, url, sem):
        super().__init__()
        self.url = url
        self.sem = sem

    def run(self):
        time.sleep(2)
        print("Download {html} success\n".format(html=self.url))
        self.sem.release()

class UrlProducer(threading.Thread):
    def __init__(self, sem):
        super().__init__()
        self.sem = sem

    def run(self):
        for i in range(20):
            self.sem.acquire()
            html_thread = HtmlSpider("https://www.baidu.com/{}".format(i), self.sem)
            html_thread.start()

if __name__ == "__main__":
    # 控制锁的数量, 每次同时会有3个线程获得锁,然后输出
    sem = threading.Semaphore(3)
    url_producer = UrlProducer(sem)
    url_producer.start()

(3) マルチプロセス プログラミングの概要

  1. マルチプロセス プログラミングでは、プロセス間でグローバル変数を共有できず、queue.Queue を使用することもできません。 used

  2. マルチプロセス プログラミング通信にはキュー、パイプの使用が必要です

  3. #プロセス プール プロセス プログラミングを使用する場合は、通信を確立するための Manger インスタンスのキュー

以上がスレッド間のリソース共有と、Python マルチスレッドで一般的に使用されるロック メカニズムの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。