这个拖后腿的“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场省赛),也取得了不错的成绩(区域赛两银),总的来说第一年就取得这成绩还是挺高兴的.我们队,我自己都渐渐的趋于成 ...
随机推荐
- 20155205 2016-2017-2 《Java程序设计》第7周学习总结
20155205 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 第十二章 只要静态方法的方法命名中参数于返回值定义相同,也可以使用静态方法来定义函数接口操作 ...
- Nodejs入门【转载】保留备用
关于 本书致力于教会你如何用Node.js来开发应用,过程中会传授你所有所需的“高级”JavaScript知识.本书绝不是一本“Hello World”的教程. 状态 你正在阅读的已经是本书的最终版. ...
- Linux上的TIME_WAIT和tcp_fin_timeout
当Linux服务器的TIME_WAIT过多时,通常会想到去修改参数降低TIME_WAIT时长,以减少TIME_WAIT数量,但Linux并没有提供这样的接口,除非重新编译内核. Linux默认的TIM ...
- 1.5sleep()方法
方法sleep()的作用是指在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)这个正在执行的线程是指this.currentThread()返回的线程. 测试如下 package com.cky.t ...
- 实战--利用HierarchicalClustering 进行基因表达聚类分析
利用建立分级树对酵母基因表达数据进行聚类分析 一.原理 根据基因表达数据,得出距离矩阵 ↓ 最初,每个点都是一个集合 每次选取距离最小的两个集合,将他们合并,然后更新这个新集合与其它点的距离 新集合与 ...
- MIT Molecular Biology 笔记5 转录机制
视频 https://www.bilibili.com/video/av7973580?from=search&seid=16993146754254492690 教材 Molecular ...
- (转)MVC语法-基础
好久没有关注微软的开发了,今天看到了MVC3,顺便学习学习,我觉得Razor是个不错的做法,比使用<%%>简单多了,而且好看.首先“_”开头的cshtml文档将不能在服务器上访问,和asp ...
- CountDownLatch同步辅助类
CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 主要方法 public CountDownLatch(int count); pu ...
- 网络编程socket、udp
PS:主机字节顺序,个位在低字节上 计算机本身不能通讯,使通过在同一主机或者不同主机内的软件进行数据传输. 套接字socket:套接字socket可以参照文件指针来理解,文件指针是表示对文件打开进行某 ...
- java基本语法、标识符、关键字
基本语法 编写Java程序时,应注意以下几点: 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的. 类名:对于所有的类来说,类名的首字母应该大写.如果类名由若干单词组 ...
