Python 多線程

一. 創建並執行線程

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)

死鎖

當有多個鎖時,兩方互相等待鎖釋放,這時就會產生死鎖。

避免死鎖的方法:

  • 銀行家算法,在程序設計時避免死鎖
  • 添加超時等待時間
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章