_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 秒になります。