老赵谈IL(4):什么时候应该学IL,该怎么学IL

2023-05-16

又是一个拖了半年的系列,可能是前几篇主要以事实为准,举例子的文章总是比较容易写的,因此十分顺畅。而最后一篇打算做一个总结,以讲道理为主——却发现该将的似乎都已经讲完了。不过做事要有始有终,该完成的也必须要完成。那么现在就来谈谈我的一些个人看法:什么时候应该学IL,以及应该怎么学IL。

对了,先表个态,我个人并支持普通程序员学习IL——至于什么是“普通”,什么叫做“学习”我们再慢慢谈。

经常听到有朋友有人说:如果要成为一个优秀的.NET程序员,那么IL很重要,一定要学习。这时候我经常会问一句“为什么”,得到的答复往往是“IL比较接近底层”。不过在我看来,“底层”只是IL本身的特性,并不足以证明“IL是高级程序员的必知必会”。IL的确比C#等高级语言来的所谓“底层”,但是IL本身其实也是一种高级抽象,它所能表现出来的几乎所有东西,都可以从C#等高级语言中获取到,而我们平时所了解到的如“装箱”,“引用类型和值类型的分配方式”,“垃圾收集”都属于CLR的范畴,您可以从书中看到或听人讲起,但是无法从IL上看出来。

当然,无论怎么说IL总是相对较为“底层”的东西,但是“底层”就应该学习吗?从不同层次可以获得不同信息,我们追求“底层”的目的肯定也不是“底层”这两个字,而是一种收获。所有人的时间或精力都是宝贵的,而对于一个优秀的程序员来说,知道了解自身需要什么,然后能够选择一个合理的层次进入,并得到更好的收益,这本身也是一种能力——而且可以说是必须的能力。这种能力不光是体现在有选择性的“学习”上,而可以体现在更多方面,因为几乎做任何一件事情都有多种方式,我们要选择最合适的。

方法,很重要。

学习IL的另一个重要“原因”,可能是有些朋友认为学习IL对于优化.NET程序性能有帮助,对于这个问题在之前的文章中也有过讨论,这次再拿出来一谈。性能优化是最需要“方法”的工作之一,如果方法不对,不仅仅是工作效率的问题,甚至很难得到正确的结果。IL和普通高级语言的代码一样,是一种静态的事物,您就算对它了解地再透彻,您也只能“阅读”它。而对于性能优化来说,要做的事情有很多,“阅读代码”在其中的重要性其实并不高——而且它也最容易误入歧途的一种。如果要进行性能优化,首先要进行的其实是“发现需要优化的地方”。徐宥写过这样一个八卦:

话说当年在贝尔实验室,一群工程师围着一个巨慢无比的小型机发呆。为啥呢,因为他们觉得这个机器太慢了。什么超频,液氮等技术都用了,这个小型机还是比不上实验室新买的一台桌上计算机。这些家伙很不爽,于是准备去优化这个机器上的操作系统。他们也不管三七二十一,就去看究竟那个进程占用CPU时间最长,然后就集中优化这个进程。他们希望这样把每个程序都优化到特别高效,机器就相对快了。于是,他们终于捕捉到一个平时居然占50% CPU的进程,而且这个进程只有大约20K的代码。他们高兴死了,立即挽起袖子敲键盘,愣是把一个20K的C语言变成了快5倍的汇编。这时候他们把此进程放到机器上这么一实验,发现居然整体效率没变化。百思不得其解的情况下他们去请教其他牛人。那个牛人就说了一句话:你们优化的进程,叫做System Idle。

无论这个八卦是否存在“艺术加工”,但都至少说明一个问题,就是如果没有经过合适的Profiling,没有找到性能的问题所在,优化是几乎不会有效果的。因此,我们一直说要把代码写的易于理解,说make clean code fast远比make fast code clean要容易,都是同样的道理,因为代码清晰,我们可以找出其性能瓶颈,然后有针对性地加以优化——那么,了解IL对此会有帮助吗?IL虽然并不难懂(稍后会谈到),但也比如C#代码要“间接”很多——试想,如果您使用阅读IL的方式来了解字符串连接的实现细节会是什么情况呢?

因为程序是动态的,动态的事情要用“动态的方式”地决定,也就是Profiling。而即便是最最普通的Profiling方式,如使用CodeTimer来统计时间,也比“阅读代码”要靠谱许多,因为它可以直接反应出不同实现方式之间运行时间的区别——而不是靠猜测。事实上您也可以发现,我在研究性能问题的时候,使用的最多的还是CodeTimer(如泛型问题、并发缓存容器、字符串连接)。的确,CodeTimer得到的只是“表象”,因此发现性能瓶颈可能还需要依赖Profiler——这也是我为什么在这个问题上尝试半天的原因。有了Profiler之后,发现性能的Hot Path便有更多依据了。

方法,很重要。

再次表达观点:我认为,对于一个“普通”的.NET程序员来说,是需要去“学习”IL的。这里的“普通”二字是针对“工作内容”,而不是“人员水平”。也就是说,和“普通程序员”相对的是“工作内容特别的程序员”而不是“高级程序员”。“特殊”是指您的工作需要“直接”用到IL,例如您如果想要写一个.NET上的新语言,就必须了解IL,了解怎样使用IL写程序。而“直接”二字自然是和“间接”二字对应,或者说您的工作中会“顺便”用到IL——例如,您像我一样想要写一个延迟加载类库,或者为NHibernate实现个通用的UserType支持——在这种情况您可能也并不需要花功夫去学它。事实上,按照我的分类方式,我也是个普通程序员,所以我没有学IL,我很难看懂复杂的IL代码,更不会用IL写程序,但这并不影响我完成一些简单的IL相关工作——这并不矛盾。

为什么这么说呢?因为IL和C#这样的高级语言实在太接近了。IL几乎只是C#的另一种表现形式,它和C#一样,都几乎直接表现出.NET中定义的各种概念:泛型、数组、类、接口、继承、异常……甚至连部分关键字都一样。还有相当重要的一点,它们都是命令式的语言,因此.NET Reflector可以将其“还原”成C#代码,因为在这个过程中实在没有丢失太多信息。但是,如果想要把IL还原成F#,这就非常困难了,因为F#和IL无法做到十分对应。因此,您在通过C#学习.NET时,已经在不断降低IL的门槛了。最后您会发现,IL真不是什么特别的东西。

于是,在用到Emit的时候,您就可以先写一些C#目标代码并编译成程序集,然后用.NET Reflector将其反编译成IL,一条一条指令地“抄”至程序中——甚至现在已经有了插件来生成这些Emit代码。同样,只要有些耐心和细心,修改个程序集可能也只是“写C#”,“反编译”,“复制/粘贴”的过程而已。

很多时候,IL也只是被“神化”了。因此会有朋友觉得,了解IL的就是高手,要成为高手必须学习IL——其实IL和水平高低的关系并不大。多说一句,即便是所谓“底层工作者”,这也是在不同抽象上办事,并不代表他们一定就是牛人。我之前谈的很多东西,其实也是想打破这个“IL神话”罢了。有时候我也纳闷,为什么Java平台上学习Byte Code或JVM的“氛围”就远不如.NET平台上学习IL和CLR呢?

当然,如果您真心希望,您感兴趣,自然可以学习IL——多了解一些总是好的。我建议,如果您真要学习IL,可以先去学习一些汇编——这么说似乎也不够确切,因为我始终认为它们的可比性并不大——只是从“表现形式”上来说,IL和汇编略有相似(例如逻辑跳转方面)。您可以先看看《深入理解计算机系统》这本书,它讲的不是IL,它讲的是“计算机系统”。在学习过程中会涉及到一些汇编——甚至您可以直接翻到对应章节学习这部分内容。您无需“学完”,只需要大概了解一下,再配合C#编程经验,就会发现IL其实“真的很直观”,此时您可能已经不太会去找一本讲IL的书去特意学习IL编程了。

嗯,“找一本讲IL的书去特意学习IL编程”,这就是我在文章开始提到的学习方式——我推荐这种做法。

相关文章

  • 老赵谈IL(1):IL是什么,它又不是什么?那么汇编呢?
  • 老赵谈IL(2):CLR内部有太多太多IL看不到的东西,包括您平时必须了解的那些
  • 老赵谈IL(3):IL可以看到的东西,其实大都也可以用C#来发现
  • 老赵谈IL(4):什么时候应该学IL,该怎么学IL
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

老赵谈IL(4):什么时候应该学IL,该怎么学IL 的相关文章

随机推荐

  • 《Programming in Lua 3》读书笔记(九)

    Part 已经看完了 xff0c 然后进入了part 阶段了 日期 xff1a 2014 7 6 Part 11 Data Structures Lua中的数据结构都是以table实现的 队列 List 61 function List n
  • 关于LINUX的NVIDIA显卡驱动安装

    LINUX 中已经集成了一些组件的相关驱动 xff0c 但是随着机器相关组件芯片不断更新 xff0c 相应的驱动程序也在不断的更新 xff0c LINUX 中集成的驱动程序难免有些不能满足需要 xff0c 其最突出的问题 xff0c 莫过于
  • 性能专题

    if与switch 当多个条件语句判断时 xff0c switch比多个if语句的性能高 转载于 https www cnblogs com lanchong archive 2011 11 03 2234180 html
  • 自制户外登山地图傻瓜书(转载)

    自制户外登山地图傻瓜书 2009 02 19 灰羊羊 转载请注明出处 第一章 前言 大概4年前喜欢上了户外运动 xff0c 从此一发不可收拾 xff0c 07年初买了一个GPS xff0c 最初只是为了避免在山中迷路 xff0c 随着使用的
  • 文件加密和解密 - 密钥存储

    当我们想要做一次加密系统 xff0c 或者只是有一个关于这个问题 xff0c 它是如何保存的加密和解密密钥 一般认为想要的文件加密和解密 xff0c 对称算法用于 一般是AES要么DES 这就存在密钥管理的问题 xff0c 它是如何 xff
  • spring mvc绑定复杂对象报错“Could not instantiate property type [com.ld.net.spider.pojo.WorkNode] to auto-gro...

    解决方法之一 xff1a 1 确保所有的Pojo都包含了默认的构造器 xff1b
  • Docker容器 暴露多个端口

    1 创建容器是指定 docker run p lt host port1 gt lt container port1 gt p lt host port2 gt lt container port2 gt 2 修改dockerfile ex
  • 巴特沃斯(Butterworth)滤波器 (1)

    下面深入浅出讲一下Butterworth原理及其代码编写 1 首先考虑一个归一化的低通滤波器 xff08 截止频率是1 xff09 xff0c 其幅度公式如下 xff1a 当n gt 时 xff0c 得到一个理想的低通滤波反馈 xff1c
  • 用预训练的densenet121模型训练cifar10数据集

    densenet121采用pytorch预训练模型 xff0c 这里用cifar10作为数据集 import torchvision models as models import ssl ssl create default https
  • Ubuntu环境下安装DBoW2

    简介 DBoW2 is an improved version of the DBow library an open source C 43 43 library for indexing and converting images in
  • java如何将二进制转换为十进制

    1 使用java内部提供的方法 xff0c 直接进行api的调用 public static void binaryTodecimal2 int n String res 61 Integer toBinaryString n System
  • Spring Cloud Feign 请求动态URL

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 FeignClient 中不要写url 使用 64 RequestLine 修饰方法 2 调用地方必须引入 FeignClientConfiguration 必须有De
  • 折半查找:查找成功的最少/多次数、平均次数,查找不成功的最少/多次数、平均次数...

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 最方面的方法是建立一个判定树 现在有11个数 xff1a xff08 第1行是索引 xff0c 第2行是数 xff09 0 1 2 3 4 5 6 7 8 9 10 7 1
  • 关于maven打包 “程序包com.sun.deploy.net不存在” 的问题

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 关于maven打包 程序包com sun deploy net不存在 的问题 遇到问题如下 xff1a INFO payGateway 1 0 SNAPSHOT SUCCE
  • 印度理工学院有多难考?

    http app myzaker com news article php pk 61 599546401bc8e08604000085 印度理工学院有多难考 xff1f 何赟08 17 原文是六月高考季时给公众号 34 中印对话 34 x
  • iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结

    今天 我对iOS系统下 的手机屏幕尺寸 分辨率 及系统版本做了一次系统总结 供大家参考 首先 是系统 xff1a 随着iOS 系统不断升级 xff0c 现在已经到iOS7 0了 xff0c 并且TA有了很多新变化 xff0c 最震撼的就是
  • android ViewFlipper的使用

    屏幕切换指的是在同一个Activity内屏幕见的切换 xff0c 最长见的情况就是在一个FrameLayout内有多个页面 xff0c 比如一个系统设置页面 xff1b 一个个性化设置页面 通过查看 OPhone API文档可以发现 xff
  • Linux下路由配置梳理

    在日常运维作业中 xff0c 经常会碰到路由表的操作 下面就linux运维中的路由操作做一梳理 xff1a 先说一些关于路由的基础知识 xff1a 1 xff09 路由概念 路由 xff1a 跨越从源主机到目标主机的一个互联网络来转发数据包
  • ASP.NET成员角色系列(一)--验证与授权入门

    在当今的信息世界里 无论是门户网站 电子商务 社区论坛 都有一个共性 它们通常都需要验证当前用户的身份并根据验证结果判断用户所具有的权限 例如博客园 它允许未注册的匿名用户可能查看帖子 但是不允许他们发表帖子 为了能够发表帖子 匿名用户必须
  • 老赵谈IL(4):什么时候应该学IL,该怎么学IL

    又是一个拖了半年的系列 xff0c 可能是前几篇主要以事实为准 xff0c 举例子的文章总是比较容易写的 xff0c 因此十分顺畅 而最后一篇打算做一个总结 xff0c 以讲道理为主 却发现该将的似乎都已经讲完了 不过做事要有始有终 xff