多任務介紹
-
現(xiàn)實生活中的多任務
有很多的場景中的事情是同時進行的有序,比如開車的時候 手和腳共同來駕駛汽車兔仰,再比如唱歌跳舞也是同時進行的跃惫;在線聽歌(邊下載邊聽歌);老師邊講邊操作等等
試想庄呈,如果把老師講課和動手操作分開鸯乃,會是什么效果蠢涝?
2.計算機中的多任務
什么叫“多任務”呢玄呛?簡單地說,就是操作系統(tǒng)可以同時運行多個任務和二。打個比方徘铝,你一邊在用瀏覽器上網(wǎng),一邊在聽MP3惯吕,一邊在用Word趕作業(yè)惕它,這就是多任務,至少同時有3個任務正在運行废登。還有很多任務悄悄地在后臺同時運行著淹魄,只是桌面上沒有顯示而已。
現(xiàn)在堡距,多核CPU已經(jīng)非常普及了甲锡,但是,即使過去的單核CPU羽戒,也可以執(zhí)行多任務缤沦。由于CPU執(zhí)行代碼都是順序執(zhí)行的,那么易稠,單核CPU是怎么執(zhí)行多任務的呢疚俱?
答案就是操作系統(tǒng)輪流讓各個任務交替執(zhí)行,任務1執(zhí)行0.01秒缩多,切換到任務2呆奕,任務2執(zhí)行0.01秒养晋,再切換到任務3,執(zhí)行0.01秒……這樣反復執(zhí)行下去梁钾。表面上看绳泉,每個任務都是交替執(zhí)行的,但是姆泻,由于CPU的執(zhí)行速度實在是太快了零酪,我們感覺就像所有任務都在同時執(zhí)行一樣。
真正的并行執(zhí)行多任務只能在多核CPU上實現(xiàn)拇勃,但是四苇,由于任務數(shù)量遠遠多于CPU的核心數(shù)量,所以方咆,操作系統(tǒng)也會自動把很多任務輪流調度到每個核心上執(zhí)行月腋。
并發(fā)與并行
并發(fā):指的是任務數(shù)多于cpu核數(shù),通過操作系統(tǒng)的各種任務調度算法瓣赂,實現(xiàn)用多個任務“一起”執(zhí)行(實際上總有一些任務不在執(zhí)行榆骚,因為切換任務的速度相當快,看上去一起執(zhí)行而已)
并行:當任務數(shù)小于或者等于cpu核數(shù)時煌集,每一個任務都有對應的cpu來處理執(zhí)行妓肢,即任務真的是一起執(zhí)行的
cpu的時間觀
# 每0.5秒獲取一次結果,保存一次結果需1秒.
import time
def get_data():
time.sleep(0.5)
print('獲取')
def save_data():
time.sleep(1)
print('保存')
t1 = time.time()
for n in range(10):
get_data()
save_data()
t2 = time.time()
print('耗時:{}'.format(t2 - t1))
改良后:
import gevent
from gevent import monkey
monkey.patch_all()
import time
from gevent import pool
all_data = []
def get_data():
time.sleep(0.5)
all_data.append(1)
print('獲取')
def save_data():
while True:
if len(all_data) > 0:
data = all_data.pop()
if data:
time.sleep(1)
print('保存')
break
else:
time.sleep(0.1)
jobs = []
p = pool.Pool()
t1 = time.time()
for n in range(10):
jobs.append(p.spawn(get_data))
jobs.append(p.spawn(save_data))
gevent.joinall(jobs)
t2 = time.time()
print('耗時:{}'.format(t2 - t1))
互斥鎖
當多個線程幾乎同時修改某一個共享數(shù)據(jù)的時候苫纤,需要進行同步控制
線程同步能夠保證多個線程安全訪問競爭資源碉钠,最簡單的同步機制是引入互斥鎖。
互斥鎖為資源引入一個狀態(tài):鎖定/非鎖定
某個線程要更改共享數(shù)據(jù)時卷拘,先將其鎖定喊废,此時資源的狀態(tài)為“鎖定”,其他線程不能更改恭金;直到該線程釋放資源操禀,將資源的狀態(tài)變成“非鎖定”褂策,其他的線程才能再次鎖定該資源横腿。互斥鎖保證了每次只有一個線程進行寫入操作斤寂,從而保證了多線程情況下數(shù)據(jù)的正確性耿焊。
.
.
.
.
.
.
.
死鎖
現(xiàn)實社會中,男女雙方都在等待對方先道歉
.
.
.
.
.
.
.
.
.
.
.
如果雙方都這樣固執(zhí)的等待對方先開口道歉遍搞,弄不好罗侯,就分手了
.
.
在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源溪猿,就會造成死鎖钩杰。
假設我們有一把藍鑰匙纫塌,可以打開一扇藍色的門;以及一把紅鑰匙讲弄,可以打開一扇紅色的門措左。兩把鑰匙被保存在一個皮箱里。同時我們定義六種行為:獲取藍鑰匙避除,打開藍色門怎披,歸還藍鑰匙,獲取紅鑰匙瓶摆,打開紅色門凉逛,歸還紅鑰匙。
游戲規(guī)則是:一個人(線程)必須通過排列六種指令的順序群井,打開兩扇門状飞,最后歸還鑰匙。
注意同一顏色的三種指令的先后順序是“取鑰匙 -> 開門 -> 還鑰匙”就可以了蝌借。比如下面這種執(zhí)行順序:
同樣的規(guī)則昔瞧,只不過換成兩個線程同時進行這個游戲,每個線程都有各自的兩扇門需要打開菩佑,但是兩個線程共享一副紅藍鑰匙自晰。
.
.
.
.
.
.
.
.
.
.
.
.
解決方案
---方法一 . 破壞互斥條件---
只有一副鑰匙稍坯,這是形成死鎖的最關鍵的原因酬荞。顯然,如果我們能在兩個線程跑之前瞧哟,能給每個線程單獨拷貝一份鑰匙的副本混巧,就能有效的避免死鎖了。
.
.
.
.
.
.
.
.
當然勤揩,這種方法試用范圍并不廣咧党。因為有時如果系統(tǒng)拷貝那副鑰匙的成本極高,而線程又很多的話陨亡,這種方法就不適用了傍衡。
.
.
.
--方法二. 破壞環(huán)路等待條件---
會出現(xiàn)死鎖的兩兩組合,一定都是一個線程先取了紅鑰匙而另一個線程先取了藍鑰匙负蠕,從而導致了可能形成了“環(huán)路等待”蛙埂。所以我們可以強制規(guī)定任何線程取鑰匙的順序只能是 “先取藍鑰匙再取紅鑰匙”的話,就能避免死鎖了
.
.
.
---方法三.破壞不剝奪條件---
除非線程自己還鑰匙遮糖,否則線程會一直占有鑰匙绣的,是形成不可剝奪條件的原因。這里,我們可以通過設置一個”最長占用時間“的閾值來解決這個問題——如果過了10分鐘仍然沒有進入下一個步驟屡江,則歸還已有的鑰匙芭概。這樣的話,兩個線程都能取到所需的鑰匙繼續(xù)下去了惩嘉。
.
.
.
.
---方法四.破壞請求和保持條件---
.
.
.
任何一個線程“貪心”谈山,都可能會導致死鎖宏怔。大致就是說有了一把鑰匙還沒還就要另一把奏路。這里我們可以通過規(guī)定在任何情況下,一個線程獲取一把鑰匙之后臊诊,必須歸還了鑰匙之后才能請求另一把鑰匙鸽粉,就可以有效解決這個問題。
.
.
.
.
其實還有一種簡單常用穩(wěn)定的方法五是抓艳?触机??
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.