執行緒層級平行(thread-level parallelism)
想像一間有好幾個廚師的廚房。如果一場盛宴能拆成彼此獨立的工作——一個廚師做湯、一個做沙拉、一個做甜點——廚師們就能同時動手,晚餐早早備妥。但有些菜必須照順序做(蛋糕沒烤好不能上糖霜),那些步驟不論你雇多少廚師都無法平行化。執行緒層級平行(thread-level parallelism)正是這件事:在程式裡找出能當成各自獨立的執行緒、同時在不同核心上跑的區塊。
執行緒(thread)是一串獨立的指令流,有自己的程式計數器和自己的工作暫存器,並與同伴執行緒共享程式的記憶體。指令層級平行(另一個概念)重疊的是單一指令流內部的微小運算,而執行緒層級平行同時跑的是整個彼此獨立的指令流。這種平行可以來自一個程式刻意生出許多執行緒來分擔一項大任務,也可以單純來自許多獨立程式一起跑。多核心晶片存在的目的,正是要兌現這種平行:給它 N 個待跑的執行緒,它就能在 N 個核心上跑到 N 個。
誠實的極限是:並非所有工作都找得到執行緒層級平行。真正循序的工作——每一步都需要前一步的結果——一點也沒有,硬把它塞到多核心上只會徒增協調開銷。即使是對平行友善的工作,也會因建立執行緒、鎖住共享資料、在同步點等待的成本而損失部分加速。執行緒層級平行在伺服器(成千上萬個獨立請求)和資料運算(把陣列切開)裡很豐沛,在一個使用者一次點一項任務時卻很稀缺。
在四個核心上加總一個百萬元素的陣列:給每個核心四分之一的陣列去加,再把四個部分和相加。四個四分之一和彼此沒有相依,所以它們以四條平行執行緒跑——接近四倍加速,只少了合併四個數字的微小最後一步。
彼此獨立的部分和能乾淨地平行;那個合併的單一步驟,就是 Amdahl 定律所警告、無法消去的循序尾巴。
執行緒層級平行談的是各自獨立的指令流,不是資料平行的 SIMD 概念(一條指令作用在許多資料元素上)。一個工作負載可能有很多前者卻完全沒有後者。