多任務
有很多的場景中的事情是同時進行的,比如開車的時候 手和腳共同來駕駛汽車僧界,再比如唱歌跳舞也是同時進行的
程序中模擬多任務
import time
def sing():
? ? for i in range(3):
? ? ? ? print("正在唱歌...%d"%i)
? ? ? ? time.sleep(1)
def dance():
? ? for i in range(3):
? ? ? ? print("正在跳舞...%d"%i)
? ? ? ? time.sleep(1)
if __name__ == '__main__':
? ? sing()
? ? dance()
多任務的理解
并行:真的多任務 cpu大于當前執(zhí)行的任務
并發(fā):假的多任務 cpu小于當前執(zhí)行的任務
線程完成多任務
import threading
import time
def demo():
? ? # 子線程
? ? print("hello girls")
? ? time.sleep(1)
if __name__ == "__main__":
? ? for i in range(5):
? ? ? ? t = threading.Thread(target=demo)
? ? ? ? t.start()
查看線程數量
threading.enumerate() 查看當前線程的數量
驗證子線程的執(zhí)行與創(chuàng)建
當調用Thread的時候侨嘀,不會創(chuàng)建線程。
當調用Thread創(chuàng)建出來的實例對象的start方法的時候捂襟,才會創(chuàng)建線程以及開始運行這個線程咬腕。
繼承Thread類創(chuàng)建線程
import threading
import time
class A(threading.Thread):
? ? def __init__(self,name):
? ? ? ? super().__init__(name=name)
? ? def run(self):
? ? ? ? for i in range(5):
? ? ? ? ? ? print(i)
if __name__ == "__main__":
? ? t = A('test_name')? ?
? ? t.start()
多線程共享全局變量(線程間通信)
修改全局變量一定需要加global嘛?
在一個函數中,對全局變量進行修改的時候葬荷,是否要加global要看是否對全局變量的指向進行了修改涨共,如果修改了指向,那么必須使用global闯狱,僅僅是修改了指向的空間中的數據煞赢,此時不用必須使用global
多線程參數-args
threading.Thread(target=test, args=(num,))
共享全局變量資源競爭
一個線程寫入,一個線程讀取,沒問題,如果兩個線程都寫入呢?
互斥鎖
當多個線程幾乎同時修改某一個共享數據的時候哄孤,需要進行同步控制
某個線程要更改共享數據時照筑,先將其鎖定,此時資源的狀態(tài)為"鎖定",其他線程不能改變瘦陈,只到該線程釋放資源凝危,將資源的狀態(tài)變成"非鎖定",其他的線程才能再次鎖定該資源晨逝《昴互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性捉貌。
創(chuàng)建鎖
mutex = threading.Lock()
鎖定
mutex.acquire()
解鎖
mutex.release()
死鎖
在線程間共享多個資源的時候支鸡,如果兩個線程分別占有一部分資源并且同時等待對方的資源冬念,就會造成死鎖。
import threading
import time
class MyThread1(threading.Thread):
? ? def run(self):
? ? ? ? # 對mutexA上鎖
? ? ? ? mutexA.acquire()
? ? ? ? # mutexA上鎖后牧挣,延時1秒急前,等待另外那個線程 把mutexB上鎖
? ? ? ? print(self.name+'----do1---up----')
? ? ? ? time.sleep(1)
? ? ? ? # 此時會堵塞,因為這個mutexB已經被另外的線程搶先上鎖了
? ? ? ? mutexB.acquire()
? ? ? ? print(self.name+'----do1---down----')
? ? ? ? mutexB.release()
? ? ? ? # 對mutexA解鎖
? ? ? ? mutexA.release()
class MyThread2(threading.Thread):
? ? def run(self):
? ? ? ? # 對mutexB上鎖
? ? ? ? mutexB.acquire()
? ? ? ? # mutexB上鎖后瀑构,延時1秒裆针,等待另外那個線程 把mutexA上鎖
? ? ? ? print(self.name+'----do2---up----')
? ? ? ? time.sleep(1)
? ? ? ? # 此時會堵塞,因為這個mutexA已經被另外的線程搶先上鎖了
? ? ? ? mutexA.acquire()
? ? ? ? print(self.name+'----do2---down----')
? ? ? ? mutexA.release()
? ? ? ? # 對mutexB解鎖
? ? ? ? mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
? ? t1 = MyThread1()
? ? t2 = MyThread2()
? ? t1.start()
? ? t2.start()
避免死鎖
????程序設計時要盡量避免
????添加超時時間等
Queue線程
在線程中寺晌,訪問一些全局變量世吨,加鎖是一個經常的過程。如果你是想把一些數據存儲到某個隊列中呻征,那么Python內置了一個線程安全的模塊叫做queue模塊耘婚。Python中的queue模塊中提供了同步的、線程安全的隊列類怕犁,包括FIFO(先進先出)隊列Queue边篮,LIFO(后入先出)隊列LifoQueue。這些隊列都實現(xiàn)了鎖原語(可以理解為原子操作奏甫,即要么不做戈轿,要么都做完),能夠在多線程中直接使用阵子∷急可以使用隊列來實現(xiàn)線程間的同步。
初始化Queue(maxsize):創(chuàng)建一個先進先出的隊列挠进。
qsize():返回隊列的大小色乾。
empty():判斷隊列是否為空。
full():判斷隊列是否滿了领突。
get():從隊列中取最后一個數據暖璧。
put():將一個數據放到隊列中。
線程同步
天貓精靈:小愛同學
小愛同學:在
天貓精靈:現(xiàn)在幾點了君旦?
小愛同學:你猜猜現(xiàn)在幾點了