• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

C#中的in参数与性能分析详解

c# 搞代码 4年前 (2022-01-09) 15次浏览 已收录 0个评论

前言

i来&源gao@dai!ma.com搞$代^码%网n 修饰符也是从 C# 7.2 开始引入的,它与我们上一篇中讨论的 《C# 中的只读结构体(readonly struct)》1 是紧密相关的。

in 修饰符

in 修饰符通过引用传递参数。 它让形参成为实参的别名,即对形参执行的任何操作都是对实参执行的。 它类似于 ref 或 out 关键字,不同之处在于 in 参数无法通过调用的方法进行修改。

  • ref 修饰符,指定参数由引用传递,可以由调用方法读取或写入。
  • out 修饰符,指定参数由引用传递,必须由调用方法写入。
  • in 修饰符,指定参数由引用传递,可以由调用方法读取,但不可以写入。

举个简单的例子:

struct Product
{
 public int ProductId { get; set; }
 public string ProductName { get; set; }
}

public static void Modify(in Product product)
{
 //product = new Product();   // 错误 CS8331 无法分配到 变量 'in Product',因为它是只读变量
 //product.ProductName = "测试商品"; // 错误 CS8332 不能分配到 变量 'in Product' 的成员,因为它是只读变量
 Console.WriteLine($"Id: {product.ProductId}, Name: {product.ProductName}"); // OK
}

引入 in 参数的原因

我们知道,结构体实例的内存在栈(stack)上进行分配,所占用的内存随声明它的类型或方法一起回收,所以通常在内存分配上它是比引用类型占有优势的。2

但是对于有些很大(比如有很多字段或属性)的结构体,将其作为方法参数,在紧凑的循环或关键代码路径中调用方法时,复制这些结构的成本就会很高。当所调用的方法不修改该参数的状态,使用新的修饰符 in 声明参数以指定此参数可以按引用安全传递,可以避免(可能产生的)高昂的复制成本,从而提高代码运行的性能。

in 参数对性能的提升

为了测试 in 修饰符对性能的提升,我定义了两个较大的结构体,一个是可变的结构体 NormalStruct,一个是只读的结构体 ReadOnlyStruct,都定义了 30 个属性,然后定义三个测试方法:

  • DoNormalLoop 方法,参数不加修饰符,传入一般结构体,这是以前比较常见的做法。
  • DoNormalLoopByIn 方法,参数加 in 修饰符,传入一般结构体。
  • DoReadOnlyLoopByIn 方法,参数加 in 修饰符,传入只读结构体。

代码如下所示:

public struct NormalStruct
{
 public decimal Number1 { get; set; }
 public decimal Number2 { get; set; }
 //...
 public decimal Number30 { get; set; }
}

public readonly struct ReadOnlyStruct
{
 public readonly decimal Number1 { get; }
 public readonly decimal Number2 { get; }
 //...
 public readonly decimal Number30 { get; }
}

public class BenchmarkClass
{
 const int loops = 50000000;
 NormalStruct normalInstance = new NormalStruct();
 ReadOnlyStruct readOnlyInstance = new ReadOnlyStruct();

 [Benchmark(Baseline = true)]
 public decimal DoNormalLoop()
 {
  decimal result = 0M;
  for (int i = 0; i < loops; i++)
  {
   result = Compute(normalInstance);
  }
  return result;
 }

 [Benchmark]
 public decimal DoNormalLoopByIn()
 {
  decimal result = 0M;
  for (int i = 0; i < loops; i++)
  {
   result = ComputeIn(in normalInstance);
  }
  return result;
 }

 [Benchmark]
 public decimal DoReadOnlyLoopByIn()
 {
  decimal result = 0M;
  for (int i = 0; i < loops; i++)
  {
   result = ComputeIn(in readOnlyInstance);
  }
  return result;
 }

 public decimal Compute(NormalStruct s)
 {
  //业务逻辑
  return 0M;
 }

 public decimal ComputeIn(in NormalStruct s)
 {
  //业务逻辑
  return 0M;
 }

 public decimal ComputeIn(in ReadOnlyStruct s)
 {
  //业务逻辑
  return 0M;
 }
}


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:C#中的in参数与性能分析详解

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址