日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

这个拖后腿的“in”

發(fā)布時間:2023/12/4 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 这个拖后腿的“in” 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

問題之源

C# 7.2推出了全新的參數(shù)修飾符in,據(jù)說是能提升一定的性能,官方MSDN文檔描述是:

Add the?in?modifier to pass an argument by reference and declare your design intent to pass arguments by reference to avoid unnecessary copying.?

然而,想當(dāng)然地使用它卻導(dǎo)致更多的副本出現(xiàn),影響代碼運行速度。

MSDN中還有一段隱含的副作用的描述:

You can call any instance method that uses by value parameters. In those instances, a copy of the?in?parameter is created.?

同時文檔也提到了readonly ref的目的:

After adding support for?in?parameters and?ref redonly?[sic] returns the problem of defensive copying will get worse since readonly variables will become more common.

?來看一下MSDN里的這個例子::

private static double CalculateDistance(in Point3D point1, in Point3D point2)

{

? ? double xDifference = point1.X - point2.X;

? ? double yDifference = point1.Y - point2.Y;

? ? double zDifference = point1.Z - point2.Z;


? ? return Math.Sqrt(xDifference * xDifference + yDifference * yDifference + zDifference * zDifference);

}

假設(shè)Point3D類型是這樣定義的:

public struct Point3D

{

? ? public Point3D(double x, double y, double z)

? ? {

? ? ? ? X = x;

? ? ? ? Y = y;

? ? ? ? Z = z;

? ? }


? ? public double X { get; }

? ? public double Y { get; }

? ? public double Z { get; }

}

結(jié)果C#的幾個本不相關(guān)的特性以一種鬧心的方式結(jié)合起來:

  • 標(biāo)記了in的結(jié)構(gòu)體參數(shù)是readonly只讀的

  • 調(diào)用標(biāo)記為readonly的結(jié)構(gòu)體的實例化方法將產(chǎn)生一個副本

    • 因為這個方法要通過改變this指針來達(dá)到確保標(biāo)記了readonly的原值不會被修改

    • 屬性訪問器也是實例方法,受this影響

    • 每次給CalculateDistance方法傳遞標(biāo)記了in的結(jié)構(gòu)體參數(shù)時,編譯器會在訪問時自動為這個參數(shù)的每個屬性創(chuàng)建一個副本,本以為不會創(chuàng)建副本,結(jié)果反而每個傳進(jìn)來的參數(shù)在方法內(nèi)部弄出來3個!

      這個問題存在已久,看一下Jon Skeet的博客:The Surprising Inefficiency of Readonly Fields。只不過使用in讓這個尷尬的場面更頻繁易現(xiàn)了。

      解決方案

      解決辦法同樣來自C# 7.2:readonly struct.

      如果將public struct Point3D改成public readonly struct Point3D,因為所有字段也已經(jīng)是readonly了,所以整個結(jié)構(gòu)體都無需改變,編譯器此時也會省掉副本的操作,只有這樣才會出現(xiàn)結(jié)構(gòu)體參數(shù)比按值傳遞獲得更快的運行速度。

      不過注意在C# 7.1中結(jié)構(gòu)體是可以通過標(biāo)記ref來傳參達(dá)到同樣避免副本開銷的。盡管如此,結(jié)構(gòu)體參數(shù)的字段想要改變值仍是可變的,甚至這個結(jié)構(gòu)體都可以指向另一個新的。在函數(shù)的參數(shù)列表中使用in的聲明主要意圖還是為了告訴調(diào)用者本函數(shù)不會去修改傳進(jìn)來的參數(shù),當(dāng)然編譯器也會配合強制保證。

      示例

      這里有一個關(guān)于in,?ref,?structreadonly struct各種組合的性能測評(結(jié)構(gòu)體size太小看不出差別,因此這個示例把結(jié)構(gòu)體增加到56 bytes以便跑出更明顯的對比效果)。結(jié)果如下:

      總結(jié)

      • 當(dāng)使用in代替ref表示設(shè)計意圖時,要明白在傳遞較大且較多的結(jié)構(gòu)體時會有微小的性能損失

      • 當(dāng)使用in又要避免產(chǎn)生副本或提高性能,在聲明結(jié)構(gòu)體時要使用readonly struct

      原文地址?http://www.cnblogs.com/BeanHsiang/p/8687780.html


      .NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    總結(jié)

    以上是生活随笔為你收集整理的这个拖后腿的“in”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。