概要:併發通常是提高執行在單處理器上的程式的效能。
“上面這句話聽起來可能會違背直覺。如果你仔細考慮一下就會發現,在單處理器上執行的併發程式開銷確實應該比該程式的所有部分都順序執行的開銷大,因為其中增加了上下文切換的代價(從一個任務切換到另一個任務)。表面上看,將程式的所有部分當作單個的任務執行好像是開銷更小一點,並且可以節省上下文切換的代價。
這個問題變得有些不同的是阻塞。如果程式中的某個任務因為該程式控制範圍之外的某些條件(通常是I/O)而導致不能繼續執行,那麼我們就說這個任務或執行緒阻塞了。如果沒有併發,則整個程式都將停止下來,直至外部條件發生變化。但是,如果使用併發來編寫程式,那麼當一個任務阻塞時,程式中的其他任務還可以繼續執行,因此這個程式可以保持繼續向前執行。事實上,從效能的角度看,如果沒有任務會阻塞,那麼在單處理機器上使用併發就沒有任何意義。” ——《Java程式設計思想》
比喻解析:
假設現在有5個人要拉屎(某個程式由多個子任務組成),5個人拉屎互不影響,不需要依賴別人(子任務各自獨立)。現在衛生間只有一個坑位。(作業系統只有一個處理器,單處理器)。如果這5個人正常拉屎的時間分別是:5,5,5,5,5.
正常情況:
如果順序執行,即按順序一個一個拉的話,不出意外的情況下,這組人總的拉屎時間是25個單位時間。
如果併發執行,也就是每人每次只有1個單位時間(時間片)可以拉屎,過了時間就換人,這樣可能頻繁換人浪費了1.5個單位時間,那麼這組人總的拉屎時間是27個單位時間。
這樣看的話,併發並沒有什麼優勢可言,反而由於頻繁換人(上下文切換)浪費了時間。
異常情況:
但是,要考慮這樣一種情況,即5個人中某個人腸胃不太好,很有可能會便祕(阻塞),這件事大家都知道(程式設計者知道,某個任務有可能會阻塞)
假設:這個腸胃不好的人是排在第二個,它要憋5單位時間,大便才能到位,然後正常排便需要花5單位時間。
如果順序執行,那剩下的3個人只能乾等著。那總拉屎時間可能是30個單位時間。
如果併發執行,這個便祕的拉不出來,1個單位時間到,就換人。但是這個人在外面依然可以醞釀,等待大便到位(大部分導致阻塞的原因是由於IO操作不到位,執行緒不佔用處理器的時間裡,可以繼續進行IO操作。)。計算下來總的時間是27+1.5 = 28.5個單位時間。
這樣的話,併發的優勢就體現出來了。
注:拉屎只能進坑拉,醞釀在哪都能醞釀(計算操作只能在佔用處理器的情況下進行,IO操作隨時都可以)
存在問題:
1.這裡案例阻塞時間的選擇不太好。
2.比喻不恰當,現實中,不存在讓人拉屎拉一半,讓出坑位的說法。