这个拖后腿的“in”
问题之源
C# 7.2推出了全新的参数修饰符in,据说是能提升一定的性能,官方MSDN文档描述是:
Add the
inmodifier to pass an argument by reference and declare your design intent to pass arguments by reference to avoid unnecessary copying.
然而,想当然地使用它却导致更多的副本出现,影响代码运行速度。
MSDN中还有一段隐含的副作用的描述:
You can call any instance method that uses by value parameters. In those instances, a copy of the
inparameter is created.
同时文档也提到了readonly ref的目的:
After adding support for
inparameters andref 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);
}
假设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; }
}
结果C#的几个本不相关的特性以一种闹心的方式结合起来:
- 标记了
in的结构体参数是readonly只读的 - 调用标记为readonly的结构体的实例化方法将产生一个副本
- 因为这个方法要通过改变this指针来达到确保标记了
readonly的原值不会被修改
- 因为这个方法要通过改变this指针来达到确保标记了
- 属性访问器也是实例方法,受this影响
每次给CalculateDistance方法传递标记了in的结构体参数时,编译器会在访问时自动为这个参数的每个属性创建一个副本,本以为不会创建副本,结果反而每个传进来的参数在方法内部弄出来3个!
这个问题存在已久,看一下Jon Skeet的博客:The Surprising Inefficiency of Readonly Fields。只不过使用in让这个尴尬的场面更频繁易现了。
解决方案
解决办法同样来自C# 7.2:readonly struct.
如果将public struct Point3D改成public readonly struct Point3D,因为所有字段也已经是readonly了,所以整个结构体都无需改变,编译器此时也会省掉副本的操作,只有这样才会出现结构体参数比按值传递获得更快的运行速度。
不过注意在C# 7.1中结构体是可以通过标记ref来传参达到同样避免副本开销的。尽管如此,结构体参数的字段想要改变值仍是可变的,甚至这个结构体都可以指向另一个新的。在函数的参数列表中使用in的声明主要意图还是为了告诉调用者本函数不会去修改传进来的参数,当然编译器也会配合强制保证。
示例
这里有一个关于in, ref, struct和readonly struct各种组合的性能测评(结构体size太小看不出差别,因此这个示例把结构体增加到56 bytes以便跑出更明显的对比效果)。结果如下:
总结
- 当使用
in代替ref表示设计意图时,要明白在传递较大且较多的结构体时会有微小的性能损失 - 当使用
in又要避免产生副本或提高性能,在声明结构体时要使用readonly struct
(原文:‘in’ will make your code slower)
这个拖后腿的“in”的更多相关文章
- 2020年9月程序员工资统计,平均14459元!你给程序员拖后腿了吗?https://jq.qq.com/?_wv=1027&k=JMPndqoM
2020年9月全国招收程序员362409人.2020年9月全国程序员平均工资14459元,工资中位数12500元,其中95%的人的工资介于5250元到35000元. 工资与上个月持平,但是岗位有所增加 ...
- 设计爬虫Hawk背后的故事
本文写于圣诞节北京下午慵懒的午后.本文偏技术向,不过应该大部分人能看懂. 五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较 ...
- ios培训机构排名
移动互联网的时代,智能手机的作用已经无所不在,APP在人们的生活中也起到了非常重要的作用,iOS开发行业同样受到越来越多人的关注,更多的人选择参加iOS培训机构来加入这个行列,而如何选择一个真正可以学 ...
- 事后分析报告(Postmortem Report)
小组讨论照片 设想和目标 1.我们的团队项目为英语单词学习助手,名为“我爱记单词”.主要提供服务包括:单词查询,单词测试,单词记忆和中英互译.目前开发的是单机版本,用户可以根据自己的需求灵活的使用相应 ...
- 《奥威Power-BI案例应用:带着漫画看报告》腾讯课程开课啦
元旦小假期过去了,不管是每天只给自己两次下床机会的你,还是唱K看电影逛街样样都嗨的你,是时候重振旗鼓,重新上路了!毕竟为了不给国家的平均工资水平拖后腿,还是要努力工作的.话说2016年已经过去了,什么 ...
- 分享自己的超轻量级高性能ORM数据访问框架Deft
Deft 简介 Deft是一个超轻量级高性能O/R mapping数据访问框架,简单易用,几分钟即可上手. Deft包含如下但不限于此的特点: 1.按照Transact-SQL的语法语义风格来设计,只 ...
- 一些对数学领域及数学研究的个人看法(转载自博士论坛wcboy)
转自:http://www.math.org.cn/forum.php?mod=viewthread&tid=14819&extra=&page=1 原作者: wcboy 现在 ...
- 8.31 js基础总结1
JavaScript是一种脚本语言,由web浏览器进行解释和执行.它给予页面灵魂,让页面可以动起来,包括动态的数据,动态的标签,动态的样式等等. 将JavaScript应用到网页中常用的方法有两种,第 ...
- 2016 ICPC China-Final 现场赛总结
距离比赛结束快有一个礼拜了才抽出时间来写这篇总结.今年比赛打了也有5场了(4场区域赛+1场省赛),也取得了不错的成绩(区域赛两银),总的来说第一年就取得这成绩还是挺高兴的.我们队,我自己都渐渐的趋于成 ...
随机推荐
- php7注意事项
1. 不要使用 mysql_ 函数 这一天终于来了,从此你不仅仅“不应该”使用mysql_函数.PHP 7 已经把它们从核心中全部移除了,也就是说你需要迁移到好得多的mysqli_函数,或者更灵活的 ...
- 后台开发 - DPDK引发的图谱
关系图谱(点击看完整大图): 部分名词: 名词 全写 解释 备注 DPDK Data Plane Development Kit 数据平面开发套件或叫数据平面开发工具集 Intel开源的快速数据包处理 ...
- slice()
提取字符串中的一部分,并返回这个新的字符串 str.slice(beginSlice[, endSlice]) 参数 beginSlice 从该索引(以 0 为基数)处开始提取原字符串中的字符.如果值 ...
- 中国剩余定理 (POJ 1006)
http://poj.org/problem?id=1006 在<孙子算经>中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩 ...
- Alpha阶段敏捷冲刺(六)
1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 祁泽文:查找了单词统计的方法. 徐璐琳:通过" ...
- Naive Bayes 笔记
Naive Bayes (朴素贝叶斯) 属于监督学习算法, 它通过计算测试样本在训练样本各个分类中的概率来确定测试样本所属分类, 取最大概率为其所属分类. 优点 在数据较少的情况下仍然有效,可以处 ...
- node.js fs,http
error: EventEmitter定义了一个特殊的时间error,它包含了‘错误’的语义,当error被发射时,EventEmitter规定如果没有 响应的监听器,Node.js会把它当做异常,退 ...
- ASP.Net Core 2.2 MVC入门到基本使用系列 (二)
本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...
- WinForm中DataGridView的使用(一) - 基本使用
数据绑定 直接指定源数据(List<T>):this.DataSource = data; 通常也可以直接指定DataTable类型的数据 DataTable dt = new DataT ...
- .NET MVC 学习笔记(六)— 数据导入
.NET MVC 学习笔记(六)—— 数据导入 在程序使用过程中,有时候需要新增大量数据,这样一条条数据去Add明显不是很友好,这时候最好就是有一个导入功能,导入所需要的数据,下面我们就一起来看一下导 ...
