多核心可擴展性
現代晶片有許多 CPU 核心——4 個、16 個、64 個或更多——而可擴展性問的是:加核心究竟能不能讓工作真的變快。理想上,把核心加倍應該讓時間減半。實務上它很少如此。想像一間廚房:多一名廚師幫助很大,但到了某個程度,太多廚師擠著同一個水槽與同一座爐子,再加人就不再有幫助,甚至拖慢進度。瓶頸從「做事」轉移到「協調誰能做事」。
在作業系統內部,主要障礙是由鎖看守的共享狀態。若許多核心都需要同一把鎖去更新同一個資料結構(比方說一個單一的全域就緒佇列),它們就排隊等待,核心被序列化而非平行執行——這就是鎖競爭。對策是減少共享:用細粒度的鎖取代一把大鎖、給每個核心各自的逐核資料讓它很少需要與他人交談,以及採用無鎖或以讀為主的技術(例如讀取複製更新 RCU),讓讀者不會被擋住。硬體效應也很要緊:快取一致性流量與偽共享(兩個核心其實碰的是不同變數,卻為同一條快取行爭鬥)會悄悄摧毀擴展性。例如 Linux 排程器就刻意維持逐核的執行佇列,正是為了讓核心不必在一把全域鎖上競爭。
這裡誠實的定律是 Amdahl 定律:只要工作中哪怕一小部分必須序列執行(一把人人都要的鎖、一個共享的計數器),無論你加多少核心,那個序列部分都會限制住加速。所以完美的線性擴展是例外而非常態。可擴展性的藝術在於把藏匿各處的序列化拔除;殘酷的現實是:總有一些會留下來。
一台伺服器在其連線表外圍只有一把全域鎖,在 4 核上跑得好好的,到 64 核卻幾乎沒更快——核心把時間都花在等那一把鎖。把該表拆成逐核的分片、各自帶一把鎖,讓核心能獨立工作,產出率終於得以隨核心數近乎線性地攀升。
一把共享的鎖讓核心序列化;逐核的資料讓它們平行執行。
更多核心不保證更快。依 Amdahl 定律,序列部分——任何必須在共享鎖下一次一個發生的工作——設下了硬上限,所以擴展靠的是移除共享,而不只是加硬體。