一. 創建並執行線程
1. threading.Thead
直接創建
用Thread(target=函數名)創建線程對象,用start根據線程對象創建線程並執行。
import threading
from threading import Thread
def hello():
print("hello world")
import time
time.sleep(1)
if __name__ == "__main__":
# 創建線程對象
t = Thread(target=hello)
# 執行線程
t.start()
# 查看所有的線程
print(threading.enumerate())
結果;
hello world
[<_MainThread(MainThread, started 4640308672)>, <Thread(Thread-1, started 123145556144128)>]
2. 繼承Thread並覆蓋run方法
import threading
from threading import Thread
class HelloThread(Thread):
def run(self):
print("hello world")
import time
time.sleep(1)
if __name__ == "__main__":
# 創建線程對象
t = HelloThread()
# 執行線程
t.start()
# 查看所有的線程
print(threading.enumerate())
結果:
hello world
[<_MainThread(MainThread, started 4657499584)>, <HelloThread(Thread-1, started 123145479835648)>]
二. 多線程共享全局變量
多線程中的變量共享與單線程的變量共享在直覺上相同。
多線程是共享全局變量的
from threading import Thread
NUM = 1
def add_num():
global NUM
NUM += 1
print("NUM in add_num is ", NUM)
def print_num():
print("NUM in print_num is ", NUM)
if __name__ == "__main__":
t1 = Thread(target=add_num)
t2 = Thread(target=print_num)
t1.start()
# 主線程等待t1執行完畢
t1.join()
t2.start()
print("NUM in main is ", NUM)
結果
NUM in add_num is 2
NUM in print_num is 2
NUM in main is 2
局部作用域
from threading import Thread
def add_num(number):
number += 1
print("NUM in add_num is ", number)
def append_3(list_):
list_.append(3)
print("list in append_3 is ", list_)
def print_num(number):
print("NUM in print_num is ", number)
def print_list(list_):
print("list in print_list is ", list_)
if __name__ == "__main__":
def start_and_join(t):
t.start()
t.join()
# 測試傳入可變類型
a_list = [1, 2]
t_list = Thread(target=append_3, args=(a_list, ))
t_print_list = Thread(target=print_list, args=(a_list, ))
start_and_join(t_list)
start_and_join(t_print_list)
print("list in main is ", a_list)
print()
# 測試傳入變量不可變類型
a_number = 10
t_number = Thread(target=add_num, args=(a_number, ))
t_print_number = Thread(target=print_num, args=(a_number, ))
start_and_join(t_number)
start_and_join(t_print_number)
print("number in main is ", a_number)
共享全局變量的問題 - 資源競爭
from threading import Thread
NUMBER = 0
LOOP = 10 ** 6
def add_number1():
global NUMBER
for i in range(LOOP):
NUMBER += 1
print("number in add_num1 is ", NUMBER)
def add_number2():
global NUMBER
for i in range(LOOP):
NUMBER += 1
print("number in add_num2 is ", NUMBER)
if __name__ == "__main__":
t1 = Thread(target=add_number1)
t2 = Thread(target=add_number2)
t1.start()
t2.start()
t1.join()
t2.join()
print("number in main is ", NUMBER)
結果
number in add_num1 is 1331562
number in add_num2 is 1336960
number in main is 1336960
使用互斥鎖解決資源競爭的問題
互斥鎖
- 創建:
mutex = threading.Lock()
- 鎖定:
mutex.acquire()
- 釋放:
mutex.release()
from threading import Thread, Lock
NUMBER = 0
LOOP = 10 ** 6
mutex = Lock()
def add_number1():
global NUMBER
for i in range(LOOP):
mutex.acquire()
NUMBER += 1
mutex.release()
print("number in add_num1 is ", NUMBER)
def add_number2():
global NUMBER
for i in range(LOOP):
mutex.acquire()
NUMBER += 1
mutex.release()
print("number in add_num2 is ", NUMBER)
if __name__ == "__main__":
t1 = Thread(target=add_number1)
t2 = Thread(target=add_number2)
t1.start()
t2.start()
t1.join()
t2.join()
print("number in main is ", NUMBER)
死鎖
當有多個鎖時,兩方互相等待鎖釋放,這時就會產生死鎖。
避免死鎖的方法:
- 銀行家算法,在程序設計時避免死鎖
- 添加超時等待時間