Python マルチスレッド プログラミングの _thread モジュール

_thread モジュールは、スレッドの派生に加えて、ロック オブジェクト (プリミティブ ロック、単純ロック、ミューテックス、ミューテックス、バイナリ セマフォとも呼ばれるロック オブジェクト) とも呼ばれる基本的な同期データ構造も提供します。

一般的に使用されるスレッド関数は次のとおりです。

関数 説明
start_new_thread(関数,引数,kwargs=なし) 新しいスレッドをフォークして、指定された引数とオプションの kwargs を使用して関数を実行します
assign_lock() LockType オブジェクトを割り当てる
出口() スレッド終了命令
LockTypeロックオブジェクトのメソッド
取得(待機=なし) ロックオブジェクトを取得してみます
ロックされた() ロック オブジェクトが取得された場合は True を返し、それ以外の場合は False を返します
リリース() ロックを解除する

_thread モジュールのコア関数は start_new_thread() です。特に新しいスレッドを生成するために使用されます。

前のセクションで onethr.py ファイルを少し変更しました。

#!/usr/bin/env python

import _thread
from time import sleep,ctime

def loop0():
    print('开始循环0次在:',ctime())
    sleep(4)
    print('结束循环0次在:',ctime())

def loop1():
    print('开始循环1次在:',ctime())
    sleep(2)
    print('结束循环1次在:',ctime())

'''    
def main():
    print('开始于:',ctime())
    loop0()
    loop1()
    print('所有的任务都完成于:',ctime())
''' 

def main():
    print('starting at:', ctime())
    _thread.start_new_thread(loop0, ())
    _thread.start_new_thread(loop1, ())
    sleep(6)
    print('all done at:', ctime())
    
if __name__ =='__main__':
    main(

スクリプトを 3 回実行すると、次の結果が得られます。

PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 21:56:10 2018
开始循环1次在: Mon Mar 26 21:56:10 2018
开始循环0次在: Mon Mar 26 21:56:10 2018
结束循环1次在: Mon Mar 26 21:56:12 2018
结束循环0次在: Mon Mar 26 21:56:14 2018
all done at: Mon Mar 26 21:56:16 2018
PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 22:00:43 2018
开始循环0次在: Mon Mar 26 22:00:43 2018
开始循环1次在: Mon Mar 26 22:00:43 2018
结束循环1次在: Mon Mar 26 22:00:45 2018
结束循环0次在: Mon Mar 26 22:00:47 2018
all done at: Mon Mar 26 22:00:49 2018
PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 22:00:56 2018
开始循环0次在: Mon Mar 26 22:00:56 2018
开始循环1次在: Mon Mar 26 22:00:56 2018
结束循环1次在: Mon Mar 26 22:00:58 2018
结束循环0次在: Mon Mar 26 22:01:00 2018
all done at: Mon Mar 26 22:01:02 2018

上記のコードからわかるように、start_new_thread() には 2 つのパラメーターが含まれている必要があります。実行される関数にパラメーターが必要ない場合でも、空のタプルを渡す必要があります。

ループ 0 またはループ 1 の開始順序が順不同である可能性があることに気付きました。ループ 0 とループ 1 は同時に実行され、ループ 1 はループ 0 より前に終了し、プログラム全体には合計 6 秒かかります。

ループ0とループ1は同時に実行されていると言えます。

メインプログラム (実際にはメインスレッド) に sleep(6) ステートメントを追加しましたが、これは実際には、メインプログラムの終了時に、loop0 スレッドとloop1 スレッドが終了していない問題を回避するためです。これは、_thread モジュールのスレッド同期メカニズムでもあります。

ただし、スレッド同期に sleep() を使用するのは信頼性が低く、これが _thread の欠点でもあると言いたいのです。

現時点では、ロック メカニズムを使用して対応するスレッド管理を実装し、同時に個々のループ関数の実装を改善できます。

import _thread
from time import sleep, ctime
#不再把4秒和2秒硬性的编码到不同的函数中,而是使用唯一的loop()函数,并把这些常量放进列表loops中
loops=[4,2]
#代替了之前的loop*()函数,三个参数分别代表了处于第几个循环中,睡眠时间和锁对象。每个循环执行到最后一句的时候,释放锁对象,告诉主线程该线程已完成
def loop(nloop,sec,lock):
    print('开始循环',nloop,'在:',ctime())
    sleep(sec)
    print('循环',nloop ,'结束于:',ctime())
    lock.release()
    
def main():
    print('开始于:',ctime())
    locks=[]
    nloops=range(len(loops))
    
    #第一个for循环中,创建了一个锁的列表,通过thread.allocate_lock()方法得到锁对象,再通过acquire()方法取到锁(相当于把锁锁上),取到之后就可以把它添加到锁列表locks中。
    for i in nloops:
        lock=_thread.allocate_lock()
        lock.acquire()
        locks.append(lock)
    #第二个for循环中,主要用于派生线程。每个线程都会调用loop()函数,并传递循环号、睡眠时间以及用于该线程的锁。  
    for i in nloops:
        _thread.start_new_thread(loop,(i,loops[i],locks[i]))
    #第三个for循环,按照顺序检查每个锁。每个线程执行完毕后,都会释放自己的锁对象。这里使用忙等待,让主线程等所有的锁都释放后才继续执行
    for i in nloops:
        while locks[i].locked():
            pass
    print('所有的任务完成于:',ctime())
    
if __name__ =='__main__':
    main()

結果:

ループ 1 の開始時刻: 2018 年 3 月 26 日月曜日 22:49:25
ループ 0 の開始時刻: 
2018 年 3 月 26 日月曜日 22:49:25 ループ 1 の終了時刻: 2018 年 3 月 26 日月曜日 22:49:27
ループ 0 の終了時刻: 2018 年 3 月 26 日月曜日22:49:29 2018
すべてのタスクが完了しました: Mon Mar 26 2018 22:49:29

上記の結果では、テーブル名の 2 つのループが同時に実行されることを除いて、プログラム全体にかかる時間は、以前の 6 秒ではなく 4 秒になります。

おすすめ

転載: blog.csdn.net/m0_59485658/article/details/129336142