CPU
為了更快的執行代碼。於是當從記憶體中讀取資料時,並不是唯讀自己想要的部分。而是讀取足夠的位元組來填入快取行。根據不同的
CPU
,快取行大小不同。如
X86
是
32BYTES
,而
ALPHA
是
64BYTES
。並且始終在第
32
個位元組或第
64
個位元組處對齊。這樣,當
CPU
訪問相鄰的資料時,就不必每次都從記憶體中讀取,提高了速度。
因為訪問記憶體要比訪問快取用的時間多得多。
但是,多核發達的年代。情況就不能那麼簡單了。試想下面這樣一個情況。
1、
CPU1
讀取了一個位元組,以及它和它相鄰的位元組被讀入
CPU1
的快取。
2、
CPU2
做了上面同樣的工作。這樣
CPU1
,
CPU2
的快取擁有同樣的資料。
3、
CPU1
修改了那個位元組,被修改後,那個位元組被放回
CPU1
的快取行。但是該資訊並沒有被寫入
RAM
。
4、
CPU2
訪問該位元組,但由於
CPU1
並未將資料寫入
RAM
,導致了資料不同步。
為瞭解決這個問題,晶片設計者制定了一個規則。當一個
CPU
修改快取行中的位元組時,電腦中的其它
CPU
會被通知,它們的快取將視為無效。於是,在上面的情況下,
CPU2
發現自己的快取中資料已無效,
CPU1
將立即把自己的資料寫回
RAM
,然後
CPU2
重新讀取該資料。
可以看出,快取行在多處理器上會導致一些不利。
從上面的情況可以看出,在設計資料結構的時候,應該盡量將唯讀資料與讀寫資料分開,並具盡量將同一時間訪問的資料群組合在一起。這樣
CPU
能一次將需要的資料讀入。
如:
Struct __a
{
Int id; //
不易變
Int factor;//
易變
Char name[64];//
不易變
Int value;//
易變
}
;
這樣的資料結構就很不利。
在
X86
下,可以試著修改和調整它
Struct __a
{
Int id; //
不易變
Char name[64];//
不易變
Char __Align[32 – sizeof(int)+sizeof(name)*sizeof(name[0])%32]
Int factor;//
易變
Int value;//
易變
Char __Align2[32 –2* sizeof(int)%32]
}
;
32 – sizeof(int)+sizeof(name)*sizeof(name[0])%32
看起來很不和諧,
32
表示
X86
中,快取行為
32BYTES
大小。
__Align
用於顯式對齊。