2016-03-26 33 views
-3

我給這寂寞的星期五晚上的任務是寫一個C#交換算法如何在C#中編寫最佳交換(T a,T b)算法?

public void Swap<T> (ref T a, ref T b) 
{ 
    // ... 
} 

上任何類或數據類型T工作,並儘可能高效。幫助批判迄今爲止建立的方法。首先,它是正確的嗎?我如何使它獲得Skeet認證?

public void Swap<T> (ref T a, ref T b) 
{ 
    // Not sure yet if T is a data or value type. 
    // Will handle swapping algorithm differently depending on each case. 
    Type type = T.GetType(); 
    if ((type.IsPrimitive()) || (type == typeof(Decimal))) 
    { 
     // this means the we can XOR a and b, the fastest way of swapping them 
     a ^= b ^= a ^= b; 
    } 
    else if (type.IsValueType()) 
    { 
     // plain old swap in this case 
     T temp = a; 
     a = b; 
     b = temp; 
    } 
    else // is class type 
    { 
     // plain old swap???   
    } 
} 

其他問題:

  • 將類型檢查的開銷抵消掉XOR任何性能優勢?
  • 如果我想優化每個案例的性能,這種處理方式對於值類型和類類型會有什麼不同?
  • 有沒有更好的方法來檢查兩個元素是否是XORable?

比方說,我希望有一個版本的方法,它的值類型,喜歡的:

public void Swap<T> (ref T a, ref T b) where T : struct 
{ 
    // 
} 

很顯然,我並不想在情況下,整個結構的副本,他們是非常大的。所以,我想這樣做C的等效++片段:

template <typename T> 
void PointerSwap<T> (T * a, T * b) 
{ 
    T * temp = a; 
    a = b; 
    b = temp; 
} 

現在,我知道,在C#中,你可以通過拳擊它們在結構進入一個類(引用類型),但是,這不是」這樣做有什麼大的開銷?有沒有辦法簡單地使用整型引用(在C++中稱爲「內存地址」)作爲參數?

C++做了這麼多比C#更多的意義......

+6

類型檢查將肯定會取消使用XOR而非常規交換的好處。 – MarcinJuraszek

+2

爲什麼不僅僅爲你的引用類型使用非常高效的'Interlocked.Exchange (T,T)'而爲顯式值類型使用重載之一而不是創建一個包裝? https://msdn.microsoft.com/en-us/library/system.threading.interlocked.exchange(v=vs.110).aspx。你的包裝在圈複雜度上有一個可測量的開銷 – MickyD

+0

@MickyD聯鎖是原子的。原子操作往往成本更高。 –

回答

9

可能對寫作「優化」最好的說法一樣,代碼是事實,這是一個單獨的語句,你聽錯了(它是否應該是C#或C++,但出於各種原因)。這交換兩個變量:

a ^= b ^= a ^= b; 

這並不:

a ^= b; 
b ^= a; 
a ^= b; 

對於這個答案的其餘部分,我會假設你的意思是後者。


我並不想在情況下,整個結構的副本,他們是非常大的。所以,我想這樣做C++代碼片段相當於:

template <typename T> 
void PointerSwap<T> (T* a, T* b) { 
    T* temp = a; 
    a = b; 
    b = temp; 
} 

[...]有沒有簡單地使用一個整數類型的參考(在C所謂的「內存地址」 ++)作爲參數的方法嗎?

您的C++代碼段無法交換兩個外部變量。相反,它只是交換兩個局部變量的值,並且就外部代碼而言它是無操作的。

在C#中,ref是實現您在此嘗試的同一事情的最簡單方法,它不會讓您在第一時間犯這個錯誤。

在任何情況下,爲什麼你會認爲像這樣涉及指針會以某種方式讓你交換值,而不在任何時候任何複製它的我不清楚。即使在你的片段中,你也沒有改變變量的位置,你仍然在移動它們包含的數據。


是否有更好的方法來檢查兩個元素是否XORable?

甚至沒有檢查(除與性能完全放棄使用反射)一個方式,因爲沒有描述類型的operator^(或類型的任何operator C#的約束,對於那件事)。你檢查過的類型是否爲BooleanByteSByteInt16UInt16Int32UInt32Int64UInt64IntPtrUIntPtrCharDoubleSingleDecimal。你會錯過任何其他類型的operator^。你也將包括類型,如Singlefloat)和Decimaldecimal),其不具有operator^開始。

即使你能可靠地檢查爲運營商,但也不能保證,要operator^通話將你想要做什麼,使交換成爲可能。這只是一個任意的方法,它可以做任何事情。

而這一切甚至不碰的事實,你不能真正呼叫操作,除非你保證你的泛型約束專門介紹類型與operator^。如果你不能這樣做,你的下一個選擇是爲每種類型T寫一個專用版本,你可以打operator^,即使所有版本看起來都一樣。要調用這些專門的方法,您需要進行單獨的類型檢查,每種類型檢查都會針對上述每種類型。而我猜想中間的恐怖陣容也會導致拳擊。


請問類型檢查的開銷抵消掉XOR任何性能優勢?

是的。

但首先,我要指出的東西:

Type type = T.GetType(); 
if (type.IsPrimitive || type == typeof(Decimal)) { 

我不知道這是否意在typeof(T)a.GetType()和您的代碼不澄清,(因爲你的代碼是無效的,它看起來有點像兩種可能性)。如果它實際上是GetType()調用而不是typeof()運算符,則應該考慮到對於值爲T的結構類型本身,typeof(T)運算符和GetType()方法將產生相同的結果,因此您可能已經離開只有這樣的:

var type = typeof(T); 
if(type.IsPrimitive || type == typeof(Decimal)) { 

在任何情況下,可以考慮這兩種方法:

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
static bool IsPrimitiveA<T>(T obj) => typeof (T).IsPrimitive; 

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
static bool IsPrimitiveB<T>(T obj) => obj.GetType().IsPrimitive; 

typeof版本發佈拆裝(在線):

55:    var a = IsPrimitiveA(1); 
001E0453 B9 BC F6 B2 71  mov   ecx,71B2F6BCh 
001E0458 E8 E1 A3 76 72  call  7294A83E 
001E045D 8B C8    mov   ecx,eax 
001E045F 8B 01    mov   eax,dword ptr [ecx] 
001E0461 8B 40 6C    mov   eax,dword ptr [eax+6Ch] 
001E0464 FF 10    call  dword ptr [eax] 
001E0466 0F B6 F8    movzx  edi,al 

GetType()版本發佈拆裝(在線):

49:    var b = IsPrimitiveB(2); 
00360464 C7 45 F4 02 00 00 00 mov   dword ptr [ebp-0Ch],2 
0036046B B9 BC F6 B2 71  mov   ecx,71B2F6BCh 
00360470 E8 7F 2C E5 FF  call  001B30F4 
00360475 8B D0    mov   edx,eax 
00360477 8B 45 F4    mov   eax,dword ptr [ebp-0Ch] 
0036047A 89 42 04    mov   dword ptr [edx+4],eax 
0036047D 8B CA    mov   ecx,edx 
0036047F 39 09    cmp   dword ptr [ecx],ecx 
00360481 E8 3E C9 62 71  call  7198CDC4 
00360486 8B C8    mov   ecx,eax 
00360488 8B 01    mov   eax,dword ptr [ecx] 
0036048A 8B 40 6C    mov   eax,dword ptr [eax+6Ch] 
0036048D FF 10    call  dword ptr [eax] 
0036048F 0F B6 F0    movzx  esi,al 
00360492 8B CF    mov   ecx,edi 
00360494 E8 5B 24 DC 71  call  721228F4 

在這兩種情況下,這大量的代碼已經 - 我們甚至還沒有開始換呢。除非天真互換進行了如此多的動作和調用,否則優化後的版本可能已經很慢了,從第一個聲明開始。


但讓我們看看一個天真版本實際上會給。參考源代碼:

static void Main(string[] args) 
{ 
    var a = 5; 
    var b = 10; 
    Swap(ref a, ref b); 
    Console.WriteLine(a); 
    Console.WriteLine(b); 
} 

通用天真交換源代碼:

static void Swap<T>(ref T a, ref T b) 
{ 
    T temp = a; 
    a = b; 
    b = temp; 
} 

非通用基於XOR的交換源代碼將永遠是這樣的形式:

static void Swap(ref ... a, ref ... b) 
{ 
    a ^= b; 
    b ^= a; 
    a ^= b; 
} 

我將展示由32位JIT編譯器生成的發佈反彙編。我省略了64位版本,因爲我看不到任何有意義的更改(偶爾使用不同的寄存器除外),但請隨時爲自己測試這些情況。我也將省略方法入口和退出樣板,即使對於非內聯方法。

這裏的天真Swap<byte>(內聯):

32:    Swap<byte>(ref a, ref b); 
00210464 0F B6 55 FC   movzx  edx,byte ptr [ebp-4] 
00210468 0F B6 45 F8   movzx  eax,byte ptr [ebp-8] 
0021046C 88 45 FC    mov   byte ptr [ebp-4],al 
0021046F 88 55 F8    mov   byte ptr [ebp-8],dl 

與XOR基於Swap(ref byte, ref byte)默認爲內聯)比較:

46:    a ^= b; 
000007FE99F204F0 0F B6 02    movzx  eax,byte ptr [rdx] 
000007FE99F204F3 30 01    xor   byte ptr [rcx],al 
    47:    b ^= a; 
000007FE99F204F5 0F B6 01    movzx  eax,byte ptr [rcx] 
000007FE99F204F8 30 02    xor   byte ptr [rdx],al 
    48:    a ^= b; 
000007FE99F204FA 0F B6 02    movzx  eax,byte ptr [rdx] 
000007FE99F204FD 30 01    xor   byte ptr [rcx],al 

這裏的天真Swap<short>(內聯):

32:    Swap<short>(ref a, ref b); 
00490464 0F BF 55 FC   movsx  edx,word ptr [ebp-4] 
00490468 0F BF 45 F8   movsx  eax,word ptr [ebp-8] 
0049046C 66 89 45 FC   mov   word ptr [ebp-4],ax 
00490470 66 89 55 F8   mov   word ptr [ebp-8],dx 

與XOR基於Swap(ref short, ref short)默認爲內聯)比較:

53:    a ^= b; 
001E0498 0F BF 02    movsx  eax,word ptr [edx] 
001E049B 66 31 01    xor   word ptr [ecx],ax 
    54:    b ^= a; 
001E049E 0F BF 01    movsx  eax,word ptr [ecx] 
001E04A1 66 31 02    xor   word ptr [edx],ax 
    55:    a ^= b; 
001E04A4 0F BF 02    movsx  eax,word ptr [edx] 
001E04A7 66 31 01    xor   word ptr [ecx],ax 

這裏的天真Swap<int>(內聯):

32:    Swap<int>(ref a, ref b); 
002E0464 8B 55 FC    mov   edx,dword ptr [ebp-4] 
002E0467 8B 45 F8    mov   eax,dword ptr [ebp-8] 
002E046A 89 45 FC    mov   dword ptr [ebp-4],eax 
002E046D 89 55 F8    mov   dword ptr [ebp-8],edx 

與XOR基於Swap(ref int, ref int)比較默認內聯):

60:    a ^= b; 
003904A0 8B 02    mov   eax,dword ptr [edx] 
003904A2 31 01    xor   dword ptr [ecx],eax 
    61:    b ^= a; 
003904A4 8B 01    mov   eax,dword ptr [ecx] 
003904A6 31 02    xor   dword ptr [edx],eax 
    62:    a ^= b; 
003904A8 8B 02    mov   eax,dword ptr [edx] 
003904AA 31 01    xor   dword ptr [ecx],eax 

這裏是t他天真Swap<long>(內聯):

33:    Swap<long>(ref a, ref b); 
001D047A 8B 75 F0    mov   esi,dword ptr [ebp-10h] 
001D047D 8B 7D F4    mov   edi,dword ptr [ebp-0Ch] 
001D0480 8B 45 E8    mov   eax,dword ptr [ebp-18h] 
001D0483 8B 55 EC    mov   edx,dword ptr [ebp-14h] 
001D0486 89 45 F0    mov   dword ptr [ebp-10h],eax 
001D0489 89 55 F4    mov   dword ptr [ebp-0Ch],edx 
001D048C 89 75 E8    mov   dword ptr [ebp-18h],esi 
001D048F 89 7D EC    mov   dword ptr [ebp-14h],edi 

與XOR基於Swap(ref long, ref long)默認爲內聯)比較:

68:    a ^= b; 
003104B6 8B 06    mov   eax,dword ptr [esi] 
003104B8 8B 56 04    mov   edx,dword ptr [esi+4] 
003104BB 33 07    xor   eax,dword ptr [edi] 
003104BD 33 57 04    xor   edx,dword ptr [edi+4] 
003104C0 89 06    mov   dword ptr [esi],eax 
003104C2 89 56 04    mov   dword ptr [esi+4],edx 
    69:    b ^= a; 
003104C5 8B 07    mov   eax,dword ptr [edi] 
003104C7 8B 57 04    mov   edx,dword ptr [edi+4] 
003104CA 33 06    xor   eax,dword ptr [esi] 
003104CC 33 56 04    xor   edx,dword ptr [esi+4] 
003104CF 89 07    mov   dword ptr [edi],eax 
003104D1 89 57 04    mov   dword ptr [edi+4],edx 
    70:    a ^= b; 
003104D4 8B 06    mov   eax,dword ptr [esi] 
003104D6 8B 56 04    mov   edx,dword ptr [esi+4] 
003104D9 33 07    xor   eax,dword ptr [edi] 
003104DB 33 57 04    xor   edx,dword ptr [edi+4] 
003104DE 89 06    mov   dword ptr [esi],eax 
003104E0 89 56 04    mov   dword ptr [esi+4],edx 

一個明顯的外賣是,基於XOR的方法似乎超過JIT編譯器默認內聯方法的限制。

[MethodImpl(MethodImplOptions.AggressiveInlining)] 

我們大會本身:幸運的是,如果裝修得當它實際上將內聯基於XOR的方法

  • 對於不大於類型dword(32 (無家族)指令,而基於異或的方法總共發出3條指令。在所有情況下,參數都在寄存器中。我沒有測量過任何時間,但是如果我不得不猜測,我會猜測寄存器之間的一個mov不會比3 xor操作慢。

  • 當您比dword大時,操作分爲單獨的dword操作。在long(64位有符號整數)的情況下,天真方法發出8 mov操作,而基於異或的方法發出12 mov操作和6 xor操作。這似乎表明,特別是對於較大的結構,天真的方法更加緊湊。


對於實驗的緣故,讓我們創建一個struct這是大如decimal和將實際申報operator^

struct Big 
{ 
    public long U; 
    public long V; 

    public static Big operator ^(Big op1, Big op2) 
    { 
     Big b; 
     b.U = op1.U^op2.U; 
     b.V = op1.V^op2.V; 
     return b; 
    } 
} 

operator^勉強足夠小,在默認情況下被內聯,所以我不希望在反彙編中看到任何呼叫。

該類型的基於XOR的Swap版本與其他版本看起來相同,所以我不重複它。

這裏的天真Swap<Big>(內聯):

94:    a ^= b; 
0027051C 8B 01    mov   eax,dword ptr [ecx] 
0027051E 8B 51 04    mov   edx,dword ptr [ecx+4] 
00270521 89 45 E4    mov   dword ptr [ebp-1Ch],eax 
    94:    a ^= b; 
00270524 89 55 E8    mov   dword ptr [ebp-18h],edx 
00270527 8B 41 08    mov   eax,dword ptr [ecx+8] 
0027052A 8B 51 0C    mov   edx,dword ptr [ecx+0Ch] 
0027052D 89 45 DC    mov   dword ptr [ebp-24h],eax 
00270530 89 55 E0    mov   dword ptr [ebp-20h],edx 
00270533 8B 06    mov   eax,dword ptr [esi] 
00270535 8B 56 04    mov   edx,dword ptr [esi+4] 
00270538 89 45 D4    mov   dword ptr [ebp-2Ch],eax 
0027053B 89 55 D8    mov   dword ptr [ebp-28h],edx 
0027053E 8B 46 08    mov   eax,dword ptr [esi+8] 
00270541 8B 56 0C    mov   edx,dword ptr [esi+0Ch] 
00270544 89 45 CC    mov   dword ptr [ebp-34h],eax 
00270547 89 55 D0    mov   dword ptr [ebp-30h],edx 
0027054A 8B 45 E4    mov   eax,dword ptr [ebp-1Ch] 
0027054D 8B 55 E8    mov   edx,dword ptr [ebp-18h] 
00270550 33 45 D4    xor   eax,dword ptr [ebp-2Ch] 
00270553 33 55 D8    xor   edx,dword ptr [ebp-28h] 
00270556 89 45 F4    mov   dword ptr [ebp-0Ch],eax 
00270559 89 55 F8    mov   dword ptr [ebp-8],edx 
0027055C 8B 45 DC    mov   eax,dword ptr [ebp-24h] 
0027055F 8B 55 E0    mov   edx,dword ptr [ebp-20h] 
00270562 33 45 CC    xor   eax,dword ptr [ebp-34h] 
00270565 33 55 D0    xor   edx,dword ptr [ebp-30h] 
00270568 89 45 EC    mov   dword ptr [ebp-14h],eax 
0027056B 89 55 F0    mov   dword ptr [ebp-10h],edx 
0027056E 8B 45 F4    mov   eax,dword ptr [ebp-0Ch] 
00270571 8B 55 F8    mov   edx,dword ptr [ebp-8] 
00270574 89 01    mov   dword ptr [ecx],eax 
00270576 89 51 04    mov   dword ptr [ecx+4],edx 
00270579 8B 45 EC    mov   eax,dword ptr [ebp-14h] 
0027057C 8B 55 F0    mov   edx,dword ptr [ebp-10h] 
0027057F 89 41 08    mov   dword ptr [ecx+8],eax 
00270582 89 51 0C    mov   dword ptr [ecx+0Ch],edx 
    95:    b ^= a; 
00270585 8B 06    mov   eax,dword ptr [esi] 
00270587 8B 56 04    mov   edx,dword ptr [esi+4] 
    95:    b ^= a; 
0027058A 89 45 B4    mov   dword ptr [ebp-4Ch],eax 
0027058D 89 55 B8    mov   dword ptr [ebp-48h],edx 
00270590 8B 46 08    mov   eax,dword ptr [esi+8] 
00270593 8B 56 0C    mov   edx,dword ptr [esi+0Ch] 
00270596 89 45 AC    mov   dword ptr [ebp-54h],eax 
00270599 89 55 B0    mov   dword ptr [ebp-50h],edx 
0027059C 8B 01    mov   eax,dword ptr [ecx] 
0027059E 8B 51 04    mov   edx,dword ptr [ecx+4] 
002705A1 89 45 A4    mov   dword ptr [ebp-5Ch],eax 
002705A4 89 55 A8    mov   dword ptr [ebp-58h],edx 
002705A7 8B 41 08    mov   eax,dword ptr [ecx+8] 
002705AA 8B 51 0C    mov   edx,dword ptr [ecx+0Ch] 
002705AD 89 45 9C    mov   dword ptr [ebp-64h],eax 
002705B0 89 55 A0    mov   dword ptr [ebp-60h],edx 
002705B3 8B 45 B4    mov   eax,dword ptr [ebp-4Ch] 
002705B6 8B 55 B8    mov   edx,dword ptr [ebp-48h] 
002705B9 33 45 A4    xor   eax,dword ptr [ebp-5Ch] 
002705BC 33 55 A8    xor   edx,dword ptr [ebp-58h] 
002705BF 89 45 C4    mov   dword ptr [ebp-3Ch],eax 
002705C2 89 55 C8    mov   dword ptr [ebp-38h],edx 
002705C5 8B 45 AC    mov   eax,dword ptr [ebp-54h] 
002705C8 8B 55 B0    mov   edx,dword ptr [ebp-50h] 
002705CB 33 45 9C    xor   eax,dword ptr [ebp-64h] 
002705CE 33 55 A0    xor   edx,dword ptr [ebp-60h] 
002705D1 89 45 BC    mov   dword ptr [ebp-44h],eax 
002705D4 89 55 C0    mov   dword ptr [ebp-40h],edx 
002705D7 8B 45 C4    mov   eax,dword ptr [ebp-3Ch] 
002705DA 8B 55 C8    mov   edx,dword ptr [ebp-38h] 
002705DD 89 06    mov   dword ptr [esi],eax 
002705DF 89 56 04    mov   dword ptr [esi+4],edx 
002705E2 8B 45 BC    mov   eax,dword ptr [ebp-44h] 
002705E5 8B 55 C0    mov   edx,dword ptr [ebp-40h] 
002705E8 89 46 08    mov   dword ptr [esi+8],eax 
002705EB 89 56 0C    mov   dword ptr [esi+0Ch],edx 
    96:    a ^= b; 
002705EE 8B 01    mov   eax,dword ptr [ecx] 
002705F0 8B 51 04    mov   edx,dword ptr [ecx+4] 
002705F3 89 45 84    mov   dword ptr [ebp-7Ch],eax 
002705F6 89 55 88    mov   dword ptr [ebp-78h],edx 
002705F9 8B 41 08    mov   eax,dword ptr [ecx+8] 
002705FC 8B 51 0C    mov   edx,dword ptr [ecx+0Ch] 
002705FF 89 85 7C FF FF FF mov   dword ptr [ebp-84h],eax 
00270605 89 55 80    mov   dword ptr [ebp-80h],edx 
00270608 8B 06    mov   eax,dword ptr [esi] 
0027060A 8B 56 04    mov   edx,dword ptr [esi+4] 
0027060D 89 85 74 FF FF FF mov   dword ptr [ebp-8Ch],eax 
00270613 89 95 78 FF FF FF mov   dword ptr [ebp-88h],edx 
00270619 8B 46 08    mov   eax,dword ptr [esi+8] 
0027061C 8B 56 0C    mov   edx,dword ptr [esi+0Ch] 
0027061F 89 85 6C FF FF FF mov   dword ptr [ebp-94h],eax 
00270625 89 95 70 FF FF FF mov   dword ptr [ebp-90h],edx 
0027062B 8B 45 84    mov   eax,dword ptr [ebp-7Ch] 
0027062E 8B 55 88    mov   edx,dword ptr [ebp-78h] 
00270631 33 85 74 FF FF FF xor   eax,dword ptr [ebp-8Ch] 
00270637 33 95 78 FF FF FF xor   edx,dword ptr [ebp-88h] 
0027063D 89 45 94    mov   dword ptr [ebp-6Ch],eax 
00270640 89 55 98    mov   dword ptr [ebp-68h],edx 
00270643 8B 85 7C FF FF FF mov   eax,dword ptr [ebp-84h] 
00270649 8B 55 80    mov   edx,dword ptr [ebp-80h] 
0027064C 33 85 6C FF FF FF xor   eax,dword ptr [ebp-94h] 
00270652 33 95 70 FF FF FF xor   edx,dword ptr [ebp-90h] 
00270658 89 45 8C    mov   dword ptr [ebp-74h],eax 
0027065B 89 55 90    mov   dword ptr [ebp-70h],edx 
0027065E 8B 45 94    mov   eax,dword ptr [ebp-6Ch] 
00270661 8B 55 98    mov   edx,dword ptr [ebp-68h] 
00270664 89 01    mov   dword ptr [ecx],eax 
00270666 89 51 04    mov   dword ptr [ecx+4],edx 
00270669 8B 45 8C    mov   eax,dword ptr [ebp-74h] 
0027066C 8B 55 90    mov   edx,dword ptr [ebp-70h] 
0027066F 89 41 08    mov   dword ptr [ecx+8],eax 
00270672 89 51 0C    mov   dword ptr [ecx+0Ch],edx 

隨着結構變得越來越大,它變得更清晰,你:

52:    Swap<Big>(ref a, ref b); 
001D0484 8B 4D EC    mov   ecx,dword ptr [ebp-14h] 
001D0487 8B 75 F0    mov   esi,dword ptr [ebp-10h] 
001D048A 8B 45 E8    mov   eax,dword ptr [ebp-18h] 
001D048D 89 45 D0    mov   dword ptr [ebp-30h],eax 
001D0490 8B FB    mov   edi,ebx 
001D0492 8B 45 DC    mov   eax,dword ptr [ebp-24h] 
001D0495 8B 55 E0    mov   edx,dword ptr [ebp-20h] 
001D0498 89 45 EC    mov   dword ptr [ebp-14h],eax 
001D049B 89 55 F0    mov   dword ptr [ebp-10h],edx 
001D049E 8B 45 D4    mov   eax,dword ptr [ebp-2Ch] 
001D04A1 8B 55 D8    mov   edx,dword ptr [ebp-28h] 
001D04A4 89 55 E8    mov   dword ptr [ebp-18h],edx 
001D04A7 8B D8    mov   ebx,eax 
001D04A9 89 4D DC    mov   dword ptr [ebp-24h],ecx 
001D04AC 89 75 E0    mov   dword ptr [ebp-20h],esi 
001D04AF 8B 45 D0    mov   eax,dword ptr [ebp-30h] 
001D04B2 89 7D D4    mov   dword ptr [ebp-2Ch],edi 
001D04B5 89 45 D8    mov   dword ptr [ebp-28h],eax 

與XOR基於Swap(ref Big, ref Big)內聯)比較用天真的方法會更好。

然而,在這裏可以看到更有趣的東西。考慮試圖阻止的Swap<T>內聯:

[MethodImpl(MethodImplOptions.NoInlining)] 
    static void Swap<T>(ref T a, ref T b) 
    { /* ... */ } 

這裏的天真Swap<Big>(內聯抑制):

93:    Big temp = a; 
004C0502 EC     in   al,dx 
004C0503 57     push  edi 
004C0504 56     push  esi 
004C0505 53     push  ebx 
004C0506 83 EC 10    sub   esp,10h 
004C0509 8B DA    mov   ebx,edx 
004C050B 8B 01    mov   eax,dword ptr [ecx] 
004C050D 8B 51 04    mov   edx,dword ptr [ecx+4] 
004C0510 89 45 EC    mov   dword ptr [ebp-14h],eax 
004C0513 89 55 F0    mov   dword ptr [ebp-10h],edx 
004C0516 8B 41 08    mov   eax,dword ptr [ecx+8] 
004C0519 8B 51 0C    mov   edx,dword ptr [ecx+0Ch] 
004C051C 89 45 E4    mov   dword ptr [ebp-1Ch],eax 
004C051F 89 55 E8    mov   dword ptr [ebp-18h],edx 
    94:    a = b; 
004C0522 8B F9    mov   edi,ecx 
004C0524 8B F3    mov   esi,ebx 
004C0526 F3 0F 7E 06   movq  xmm0,mmword ptr [esi] 
004C052A 66 0F D6 07   movq  mmword ptr [edi],xmm0 
004C052E F3 0F 7E 46 08  movq  xmm0,mmword ptr [esi+8] 
004C0533 66 0F D6 47 08  movq  mmword ptr [edi+8],xmm0 
    95:    b = temp; 
004C0538 8B 45 EC    mov   eax,dword ptr [ebp-14h] 
004C053B 8B 55 F0    mov   edx,dword ptr [ebp-10h] 
004C053E 89 03    mov   dword ptr [ebx],eax 
004C0540 89 53 04    mov   dword ptr [ebx+4],edx 
004C0543 8B 45 E4    mov   eax,dword ptr [ebp-1Ch] 
004C0546 8B 55 E8    mov   edx,dword ptr [ebp-18h] 
004C0549 89 43 08    mov   dword ptr [ebx+8],eax 
004C054C 89 53 0C    mov   dword ptr [ebx+0Ch],edx 

現在開始發射SSE指令! decimal和其他大型結構可以觀察到相同的行爲。

在我測試的任何環境下,基於XOR的方法不會生成SSE指令。


讓我們嘗試用類:

public class W<T> 
{ 
    public T Value; 
} 

這裏的天真Swap<W<T>>(內聯):

61:    Swap(ref a, ref b); 
0023047E 8B 55 FC    mov   edx,dword ptr [ebp-4] 
00230481 8B 45 F8    mov   eax,dword ptr [ebp-8] 
00230484 89 45 FC    mov   dword ptr [ebp-4],eax 
00230487 89 55 F8    mov   dword ptr [ebp-8],edx 

這是非常簡單的 - 它有效地是一個int交換,如上。

引用是不透明的,因此基於XOR的方法對這些類型沒有意義。因此,在這種情況下,沒有等效的反彙編。


對於類型,如floatdoubledecimal有應用XOR操作沒有優雅的方式。一個(可能是愚蠢的)方法,使之能夠在所有是創建一個聯盟,其中有是非通用:

[StructLayout(LayoutKind.Explicit)] 
struct XORFloat 
{ 
    [FieldOffset(0)] public int Bits; 
    [FieldOffset(0)] public float Value; 
} 

然後嘗試這樣的:

static void Swap(ref float a, ref float b) 
{ 
    var _a = default(XORFloat); 
    var _b = default(XORFloat); 
    _a.Value = a; 
    _b.Value = b; 
    _a.Bits ^= _b.Bits; 
    _b.Bits ^= _a.Bits; 
    _a.Bits ^= _b.Bits; 
    a = _a.Value; 
    b = _b.Value; 
} 

但這似乎打敗整個基於異或的方法,因爲它會明顯涉及很多mov操作。

這裏的天真Swap<float>(內聯):

153:    var _a = default(XORFloat); 
0035049F 33 C0    xor   eax,eax 
003504A1 89 45 F8    mov   dword ptr [ebp-8],eax 
003504A4 89 45 F4    mov   dword ptr [ebp-0Ch],eax 
003504A7 8D 45 F8    lea   eax,[ebp-8] 
003504AA 33 F6    xor   esi,esi 
003504AC 89 30    mov   dword ptr [eax],esi 
    154:    var _b = default(XORFloat); 
003504AE 8D 45 F4    lea   eax,[ebp-0Ch] 
003504B1 89 30    mov   dword ptr [eax],esi 
    155:    _a.Value = a; 
003504B3 D9 01    fld   dword ptr [ecx] 
003504B5 D9 5D F8    fstp  dword ptr [ebp-8] 
    156:    _b.Value = b; 
003504B8 D9 02    fld   dword ptr [edx] 
003504BA D9 5D F4    fstp  dword ptr [ebp-0Ch] 
    157:    _a.Bits ^= _b.Bits; 
003504BD 8D 75 F8    lea   esi,[ebp-8] 
003504C0 8B 45 F4    mov   eax,dword ptr [ebp-0Ch] 
003504C3 31 06    xor   dword ptr [esi],eax 
    158:    _b.Bits ^= _a.Bits; 
003504C5 8D 75 F4    lea   esi,[ebp-0Ch] 
003504C8 8B 45 F8    mov   eax,dword ptr [ebp-8] 
003504CB 31 06    xor   dword ptr [esi],eax 
    159:    _a.Bits ^= _b.Bits; 
003504CD 8D 75 F8    lea   esi,[ebp-8] 
003504D0 8B 45 F4    mov   eax,dword ptr [ebp-0Ch] 
003504D3 31 06    xor   dword ptr [esi],eax 
    160:    a = _a.Value; 
003504D5 D9 45 F8    fld   dword ptr [ebp-8] 
003504D8 D9 19    fstp  dword ptr [ecx] 
    161:    b = _b.Value; 
003504DA D9 45 F4    fld   dword ptr [ebp-0Ch] 
003504DD D9 1A    fstp  dword ptr [edx] 

19:    Swap<float>(ref a, ref b); 
00252DC4 D9 45 FC    fld   dword ptr [ebp-4] 
00252DC7 D9 45 F8    fld   dword ptr [ebp-8] 
00252DCA D9 5D FC    fstp  dword ptr [ebp-4] 
00252DCD D9 5D F8    fstp  dword ptr [ebp-8] 

與XOR爲基礎(和工會爲主)Swap(ref float, ref float)默認爲內聯)比較

總之,我會說使用明顯天真的Swap,讓編譯器弄清楚你的意思,並做好自己的工作。有更多有趣的事情需要修補。

+0

附錄(由於字符限制):您*可以*在C#中使用指針,但僅限於特定種類的結構。不幸的是,沒有描述這些結構的通用約束,所以你不能有'T'指針。 –

相關問題