首頁 > 軟體

python 包之 threading 多執行緒

2022-04-02 13:01:19

一、建立一個執行緒

  • 通過範例化threading.Thread類建立執行緒
import threading

def func(s):
print(s)

if __name__ == '__main__':
# 建立執行緒
thread = threading.Thread(target=func, args=('hello',))
# 啟動執行緒
thread.start()
# 等待執行緒結束
thread.join()

二、建立多個執行緒

import threading

def func(s):
print(s)

if __name__ == '__main__':
thread = [
threading.Thread(target=func, args=('1', ))
threading.Thread(target=func, args=('2', ))
]

[t.start() for t in thread]
[t.join() for t in thread]

三、執行緒同步

  • 使用鎖實現執行緒同步
  • threading.Lock是直接通過_thread模組擴充套件實現的
  • 鎖只有“鎖定”和“非鎖定”兩種狀態
  • 同一個執行緒獲取鎖後,如果在釋放鎖之前再次獲取鎖會導致當前執行緒阻塞,除非有另外的執行緒來釋放鎖,如果只有一個執行緒,並且發生了這種情況,會導致這個執行緒一直阻塞下去,即形成了死鎖。
import time
import threading

# 建立鎖
lock = threading.Lock()
# 全域性變數
global_resource = [None] * 5

def change_resource(para, sleep):
# 請求鎖
lock.acquire()
# 這段程式碼如果不加鎖,第一個執行緒執行結束後global_resource中是亂的,輸出為:結果是: ['hello', 'hi', 'hi', 'hello', 'hello']
# 第二個執行緒執行結束後,global_resource中還是亂的,輸出為:結果是: ['hello', 'hi', 'hi', 'hi', 'hi']
global global_resource
for i in range(len(global_resource)):
global_resource[i] = para
time.sleep(sleep)
print("結果是:", global_resource)

# 釋放鎖
lock.release()

if __name__ == '__main__':
thread = [
threading.Thread(target=change_resource, args=('hi', 2))
threading.Thread(target=change_resource, args=('hello', 1))
]

[t.start() for t in thread]
[t.join() for t in thread]

# 結果是: ['hi', 'hi', 'hi', 'hi', 'hi']
# 結果是: ['hello', 'hello', 'hello', 'hello', 'hello']

四、遞迴鎖

  • 上面執行緒同步使用的是普通鎖,也就是隻有鎖的狀態,並不知道是哪個執行緒加的鎖
  • 這樣的話使用普通鎖時,對於一些可能造成死鎖的情況,可以考慮使用遞迴鎖來解決
  • 遞迴鎖和普通鎖的差別在於加入了“所屬執行緒”和“遞迴等級”的概念
  • 釋放鎖必須有獲取鎖的執行緒來進行釋放
import time
import threading

# 使用成一個遞迴鎖就可以解決當前這種死鎖情況
rlock_hi = rlock_hello = threading.RLock()

def test_thread_hi():
# 初始時鎖內部的遞迴等級為1
rlock_hi.acquire()
print('執行緒test_thread_hi獲得了鎖rlock_hi')
time.sleep(2)
# 如果再次獲取同樣一把鎖,則不會阻塞,只是內部的遞迴等級加1
rlock_hello.acquire()
print('執行緒test_thread_hi獲得了鎖rlock_hello')
# 釋放一次鎖,內部遞迴等級減1
rlock_hello.release()
# 這裡再次減,當遞迴等級為0時,其他執行緒才可獲取到此鎖
rlock_hi.release()

def test_thread_hello():
rlock_hello.acquire()
print('執行緒test_thread_hello獲得了鎖rlock_hello')
time.sleep(2)
rlock_hi.acquire()
print('執行緒test_thread_hello獲得了鎖rlock_hi')
rlock_hi.release()
rlock_hello.release()

if __name__ == '__main__':
thread = [
threading.Thread(target=test_thread_hi)
threading.Thread(target=test_thread_hello)
]

[t.start() for t in thread]
[t.join() for t in thread]

五、訊號鎖

  • 一個號誌管理一個內部計數器
  • acquire()方法會減少計數器,release()方法則增加計數器
  • 計數器的值永遠不會小於零
  • 當呼叫acquire()時,如果發現該計數器為零,則阻塞執行緒
  • 直到呼叫release()方法使計數器增加。
import time
import threading

# 建立號誌物件,初始化計數器值為3
semaphore3 = threading.Semaphore(3)


def thread_semaphore(index):
# 號誌計數器減1
semaphore3.acquire()
time.sleep(2)
print('thread_%s is running...' % index)
# 號誌計數器加1
semaphore3.release()


if __name__ == '__main__':
# 雖然會有9個執行緒執行,但是通過號誌控制同時只能有3個執行緒執行
# 第4個執行緒啟動時,呼叫acquire發現計數器為0了,所以就會阻塞等待計數器大於0的時候
for index in range(9):
threading.Thread(target=thread_semaphore, args=(index, )).start()

到此這篇關於python 包之 threading 多執行緒的文章就介紹到這了,更多相關threading 多執行緒內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com