簡體   English   中英

IntPtr演員與新演員

[英]IntPtr cast vs. new

我只是看一個例子,在其中我看到了代碼

return new IntPtr(handle);

在探索我們的代碼之后,我發現我們已經使用了類似的模式,但在我們的代碼中我們幾乎有相同的東西:

return (IntPtr)handle;

這兩種情況有區別嗎? 第二個是否會以任何方式“更好”,因為它不會分配新的內存,或者只是隱藏相同的構造函數?

在你的例子中,我猜測句柄是一個整數值? IntPtr聲明從Int32(int)和Int64(long)的顯式轉換,它只調用相同的構造函數:

public static explicit operator IntPtr(int value)
{
    return new IntPtr(value);
}

因此除了可能的可讀性問題之外,實際上沒有區別。

反射器說,無論如何,演員都在調用引擎蓋下的構造函數:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct IntPtr : ISerializable
{
    ...

    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
    public static explicit operator IntPtr(int value)
    {
        return new IntPtr(value);
    }

}

所以這個線程都是談話而沒有數字,所以讓我們談談指標。 我運行了一些測試代碼,以使用Visual Studio 2010獲得一些性能指標

我通過計算10個測試運行中的任一方法的平均時間來獲得這些度量,其中每個在Debug然后釋放模式中進行1000萬次迭代(非優化然后優化):

(調試)轉換方法:~32 ms分配方法:~26 ms

(發布)投射方法:~20 ms分配方法:~22 ms

同樣有趣的是,僅使用gcnew將這些指標與托管C ++的類似代碼進行比較,結果會有很大差異。

再次設置相同。 除了比較鑄造方法:“IntPtr ^ ptr =(IntPtr)i;” vs分配方法:“IntPtr ^ ptr =(IntPtr)i;”。

(調試)轉換方法:~91ms分配方法:~127ms

(發布)施法方法:~22ms分配方法:~124ms

現在,如果你正在輕描淡寫地說好,為什么C#比托管C ++快得多,答案是不是。 使用IntPtr的最有效方法是作為值類型而不是對值類型的引用。 例如像“IntPtr ptr =(IntPtr)i;”。 這將為您提供~24ms(Debug more)或(~22 Release模式)。 看看編譯器如何優化它以獲得22ms而不是90ms。

在C#中的結論,除非你正在看真正的緊密代碼,否則無關緊要。 我認為我在Release中的代碼實際上是在優化演員,因為評論演員給出了相同的~22ms。 但是在大多數情況下,編譯器會在C#中重新使用這個,至少VS 2010。 但是,在托管C ++ / CLI中,如果您正在查看具有最小性能約束的代碼,那么請注意。 編譯器不會自動優化對cast方法的gcnew分配,而且幾乎快了6倍......我實際上遇到了C ++ / CLI中的這個特殊問題,這導致我在處理一些實時音頻時發布在這個線程上處理。 我的代碼(C#):(我的托管C ++代碼非常相似,除了我自己編寫Average()並使用控制台輸出而不是消息框)。

    static void Main()
    {
        List<int> castTimings = new List<int>();
        List<int> allocTimings = new List<int>();

        for (int i = 0; i < TEST_RUNS; ++i)
        {
            castTimings.Add(RunCastMethod().Milliseconds);
            allocTimings.Add(RunAllocationMethod().Milliseconds);
        }

        MessageBox.Show(string.Format("Casting Method took: {0}ms", castTimings.Average() ));
        MessageBox.Show(string.Format("Allocation Method took: {0}ms", allocTimings.Average() ));
    }

    private static TimeSpan RunAllocationMethod() {
        DateTime start = DateTime.Now;

        for (int i = 0; i < TEST_ITERATIONS; ++i)
        {
            IntPtr ptr = new IntPtr(i);
        }

        return ( DateTime.Now - start );
    }

    private static TimeSpan RunCastMethod()
    {
        DateTime start = DateTime.Now;

        for (int i = 0; i < TEST_ITERATIONS; ++i)
        {
            IntPtr ptr = (IntPtr) i;
        }

        return (DateTime.Now - start);
    }

由於IntPtr是值類型,因此使用new不會分配任何內存。

從技術上講,調用仍然編譯為不同的IL - 一個實際調用構造函數,另一個調用顯式轉換運算符。 我不確定在JIT通過之后這兩者之間是否存在任何實際差異 - 但很可能沒有(盡管我懷疑你在實踐中注意到這兩種方式,這是一種femtooptimization)。

無論如何,演員比使用構造函數更慣用,所以我建議單獨使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM