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

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

Oct 26, 2018 pm 05:18 PM
Pythonマルチスレッド

この記事では、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 サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? Apr 01, 2025 pm 05:09 PM

LinuxターミナルでPythonバージョンを表示する際の許可の問題の解決策PythonターミナルでPythonバージョンを表示しようとするとき、Pythonを入力してください...

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? Apr 01, 2025 pm 11:15 PM

PythonのPandasライブラリを使用する場合、異なる構造を持つ2つのデータフレーム間で列全体をコピーする方法は一般的な問題です。 2つのデータがあるとします...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? 中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? Apr 01, 2025 pm 10:51 PM

UvicornはどのようにしてHTTPリクエストを継続的に聞きますか? Uvicornは、ASGIに基づく軽量のWebサーバーです。そのコア機能の1つは、HTTPリクエストを聞いて続行することです...

文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? 文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? Apr 01, 2025 pm 11:18 PM

Pythonでは、文字列を介してオブジェクトを動的に作成し、そのメソッドを呼び出す方法は?これは一般的なプログラミング要件です。特に構成または実行する必要がある場合は...

See all articles