多執行緒的好處
假設你是服務台唯一的櫃員,一位客人要你打電話給一個動作很慢的倉庫,並在線上等候十分鐘。如果你一次只處理一位客人,那麼你握著電話等的時候,排隊的其他客人只能站在那裡乾著急。比較好的服務台會有好幾位櫃員,共用同一批檔案與同一間後台:一位可以掛在線上等,其他人繼續服務客人。多執行緒就是放進單一程式裡的那種「多櫃員」服務台,好幾條工作流共用一套資源,於是程式不會因為某一部分必須等待就整個卡住。
人們選用執行緒,通常出於四個經典理由。反應性:程式可以在一個執行緒上持續對使用者作出反應(重繪視窗、接受點擊),同時把緩慢的操作放在另一個執行緒上跑,於是看起來不會卡死。靠平行取得加速:在有多個 CPU 核心的機器上,不同執行緒可以真的在同一瞬間執行,所以把一個大工作切給多個執行緒可以更快完成。資源共享:同一行程裡的執行緒本來就共享記憶體與檔案,因此彼此交換資料不需要複製、也不需要特別的通道。經濟性:執行緒的建立與切換都比一整個行程便宜許多,因為它重複利用了行程的位址空間與資源。
兩點誠實的提醒。第一,即使只有單一核心,執行緒也能換來反應性(把等待和工作重疊起來),但只有在你有多個核心、而且工作真的能被分割時,才換得到真正的加速。第二,加速永遠達不到核心數的完整倍數:任何工作都有部分必須循序執行,這個循序比例會限制能得到的加速(一個經驗法則叫阿姆達爾定律,Amdahl's law)。而且每一項好處都要付出正確性的代價,共享可變狀態意味著你現在必須去推敲競爭問題,這正是並行程式設計困難的地方。
一個照片應用程式要對一張五千萬畫素的影像套用濾鏡,可以把影像切成八條橫帶,分給八個執行緒各處理一條。在八核心的 CPU 上,濾鏡大約只要原本八分之一的時間就能完成,同時第九個執行緒讓進度條持續移動,使視窗依然感覺有反應。
反應性、平行加速、共享、經濟性,這就是採用執行緒的四個理由。
多執行緒不會讓單核心機器同時做兩件運算,在那裡它只能把等待和工作重疊起來。真正同時的運算需要多個核心,而即便如此,工作中循序的部分仍會限制能得到的加速。