[英]Global variable reads inside tight loops in C
假設我在 C 中有一個緊密循環,在其中我使用全局變量的值來執行一些算術運算,例如
double c;
// ... initialize c somehow ...
double f(double*a, int n) {
double sum = 0.0;
int i;
for (i = 0; i < n; i++) {
sum += a[i]*c;
}
return sum;
}
使用c
全局變量。 c
是否在每次循環迭代中“從全局范圍重新讀取”? 畢竟,它可能已被執行其他 function 的其他線程更改,對吧? 因此,通過在循環之前獲取c
的本地(函數堆棧)副本並僅使用此副本,代碼會更快嗎?
double f(double*a, int n) {
double sum = 0.0;
int i;
double c_cp = c;
for (i = 0; i < n; i++) {
sum += a[i]*c_cp;
}
return sum;
}
雖然我沒有具體說明c
是如何初始化的,但我們假設它是以某種方式完成的,因此在編譯時該值是未知的。 此外, c
在整個運行時實際上是一個常量,即我作為程序員知道它的值不會改變。 我可以讓編譯器了解這些信息嗎,例如在全局 scope 中使用static double c
c? 這會改變a[i]*c
與a[i]*c_cp
問題嗎?
任何相當聰明的編譯器都會優化您的代碼,因此它會像您的第二個代碼片段一樣運行。 使用static
不會有太大變化,但如果您想確保每次迭代都讀取,則使用volatile
。
關於來自不同線程的更改的要點。 就單線程執行而言,編譯器將保持代碼的完整性。 這意味着它可以重新排序您的代碼,跳過某些內容,添加某些內容——只要最終結果仍然相同。
對於多線程,您的工作是確保事情仍然按特定順序發生,而不僅僅是最終結果是正確的。 確保的方式是memory障礙。 這是一個有趣的話題,但除非您是專家,否則最好避免閱讀。
一旦所有內容都翻譯成機器代碼,您將不會有任何區別。 如果 c 是全局的,則對 c 的任何訪問都將引用 c 的地址,或者最有可能在緊密循環中將 c 保存在寄存器中,或者在最壞的情況下保存在 L1 緩存中。
在 Linux 機器上,您可以輕松生成程序集並檢查生成的代碼。
您還可以運行基准測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.