- 什麼叫多任務呢?
- 在現實生活中,有不少場景是同時進行的,好比唱歌跳舞,試想若是把這二者分開來,該有多滑稽。
- 多任務其實就是操做系統同時處理多個任務,處理多任務得有多核處理器,因此在多核處理器普及以後,真正的多任務才實現。
- 多任務能夠分爲併發和並行,其中併發是「假多任務」,即單核處理器在極短的時間內循環處理多個任務,極短的時間給人形成一種「多任務」的錯覺;而並行是「真多任務」,即每一個核處理一個任務。
- Python的多任務實現方式可分爲「進程」,「線程」,「協程」,其中進程佔用資源最大,可是穩定,線程佔用資源和穩定性處於三者中間,協程是輕量級的,穩定性也較差一點。
什麼是「線程」呢?線程能夠理解爲程序中能夠執行的一個分支。程序默認是有一個線程的,稱爲「主線程」,這個線程負責從上至下執行程序。在從上至下執行的過程當中,有時候須要程序裏面的多個函數一塊兒執行,這時候就須要用到「多線程」。python
Python建立多線程可使用threading模塊,下面看看我是怎麼實現一下邊唱歌邊跳舞的:多線程
import time
import threading
def sing():
for i in range(5):
print("sing")
time.sleep(1)
def dance():
for i in range(5):
print("dance")
time.sleep(1)
def main():
t1 = threading.Thread(target=sing) # 建立子線程
t2 = threading.Thread(target=dance)
t1.start() # 子線程開始執行
t2.start()
if __name__ == "__main__":
main()
複製代碼
注意:併發
threading裏面有個enumerate()方法能夠查看當前有哪些線程中運行,代碼以下:函數
import threading
import time
def test1():
for i in range(5):
print("-----test1-----%d---" % i)
time.sleep(1)
def test2():
for i in range(5):
print("-----test2-----%d---" % i)
time.sleep(1)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
time.sleep(1)
t2.start()
time.sleep(1)
while True:
print(threading.enumerate)
time.sleep(1)
if __name__ == "__main__":
main()
複製代碼
多線程之間是共享全局變量的,但多線程中共享全局變量有個缺點是會出現競爭,如何解決資源競爭呢,這就涉及到「互斥鎖」。ui
互斥鎖的出現是爲了解決幾個線程之間產生的資源競爭,當多個線程須要同時進行一個全局變量進行處理的時候,互斥鎖就派上用場了。這就跟上廁所關門同樣,你關上門以後就不容許其餘人進入這個廁所。 某個線程要更改共享數據時,先將其鎖定,此時資源的狀態爲「鎖定」,其餘線程不能修改,直到該線程釋放資源,資源的狀態變爲「非鎖定」,其餘的線程才能再次鎖定該資源。spa
import threading
import time
# 定義一個全局變量
g_num = 0
def test1(num):
global g_num
# 通常上鎖會上在代碼儘可能少的地方,省得形成一個程序上鎖以後長時間不解鎖的狀況
for i in range(num):
# 上鎖,若是以前沒有被上鎖,那麼此時上鎖成功,
# 若是以前已經被上鎖,那麼此時被堵塞,知道鎖被解開
mutex.acquire()
g_num += 1
# 解鎖
mutex.release()
print("-------in test1 g_num=%d-----" % g_num)
def test2(num):
global g_num
for i in range(num):
mutex.acquire()
g_num += 1
# 解鎖
mutex.release()
print("-------in test2 g_num=%d-----" % g_num)
# 建立一個互斥鎖,默認沒有上鎖
mutex = threading.Lock()
def main():
t1 = threading.Thread(target=test1, args=(1000000,))
t2 = threading.Thread(target=test2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print("-------in main Thread g_num = %d----" % g_num)
if __name__ == '__main__':
main()
複製代碼
結果操作系統
-------in main Thread g_num = 933690----
-------in test1 g_num=1999178-----
-------in test2 g_num=2000000-----
複製代碼
爲何主線程會出如今子線程以前呢,這個是由於這5秒以內子線程沒有完成計算形成的。線程
線程是在「進程」,「線程」,「協程」之間處於「老二」的地位的,通常在咱們寫程序裏面仍是常常用到線程的,好比音樂播放器的邊播放和邊下載。code