码农的荒岛求生

其他

彻底理解高级I/O:零拷贝

大家好,我是小风哥,今天和大家简单聊聊零拷贝。计算机处理的任务大体可以分为两类:CPU密集型与IO密集型。当前流行的互联网应用更多的属于IO密集型,传统的IO标准接口都是基于数据拷贝的,这篇文章我们主要关注该怎样从数据拷贝的角度来优化IO性能。为什么IO接口要基于数据拷贝?为了让广大码农们更好的沉迷于自己的一亩三分地,防止ta们分心去关心计算机中的硬件资源分配问题,操作系统诞生了。操作系统本质上就是一个管家,目的就是更加公平合理的给各个进程分配硬件资源,在操作系统出现之前,程序员需要直面各类硬件,就像这样:在这一时期程序员真可谓掌控全局,掌控全局带来的后果就是你需要掌控所有细节,这显然不利于生产力的释放。操作系统应用而生。计算机系统就变成这样了:现在应用程序不需要和硬件直接交互了,仅从IO的角度上看,操作系统变成了一个类似路由器的角色,把应用程序递交过来的数据分发到具体的硬件上去,或者从硬件接收数据并分发给相应的进程。数据传递是通过什么呢?就是我们常说的buffer,所谓buffer就是一块可用的内存空间,用来暂存数据。操作系统这一中间商导致的问题就是:你需要首先把东西交给操作系统,操作系统再转手交给硬件,这就必然涉及到数据拷贝。这就是为什么传统的IO操作必然需要进行数据拷贝的原因所在。关于操作系统系统完整的阐述请参见博主的《深入理解操作系统》。然而数据拷贝是有性能损耗的,接下来我们用一个实例来让大家对该问题有一个更直观的认知。网络服务器浏览器打开一个网页需要很多数据,包括看到的图片、html文件、css文件、js文件等等,当浏览器请求这类文件时服务器端的工作其实是非常简单的:服务器只需要从磁盘中抓出该文件然后丢给网络发送出去。代码基本上类似这样:read(fileDesc,
4月29日 上午 8:11
其他

彻底理解编译器工作原理

大家好,我是小风哥,这是一篇首发于2020年8月的文章,看自己三年前写的文字有种时空穿越的感觉,在这里也鼓励大家尝试记录下点什么东西,以证明这个世间我们曾经来过,话不多说,以下是正文。对于程序员来说编译器是非常熟悉的,每天都在用,但是当你在点击“Run”这个按钮或者执行编译命令时你知道编译器是怎样工作的吗?这篇文章就为你解答这个问题。编译器就是一个普通程序,没什么大不了的什么是编译器?编译器是一个将高级语言翻译为低级语言的程序。首先我们一定要意识到编译器就是一个普通程序,没什么大不了的。在没有弄明白编译器如何工作之前你可以简单的把编译器当做一个黑盒子,其作用就是输入一个文本文件输出一个二进制文件。基本上编译器经过了以下几个阶段,等等,这句话教科书上也有,但是我相信很多同学其实并没有真正理解这几个步骤到底在说些什么,为了让你彻底理解这几个步骤,我们用一个简单的例子来讲解。假定我们有一段程序:while
2023年12月15日
其他

彻底理解IO多路复用

大家好,我是小风哥,有很多同学问能不能发下之前的文章,后续我会找一些之前阅读量不错的发下,本文首发于2021年1月,以下是正文。在讲解该技术之前,我们需要预习一下文件以及文件描述符。什么是文件程序员使用I/O最终都逃不过文件这个概念。在Linux世界中文件是一个很简单的概念,作为程序员我们只需要将其理解为一个N
2023年11月7日
其他

原来微信小程序可以直接在自己App上架了

小程序≠微信小程序说到小程序,大部分的读者第一反应,可能是微信小程序、支付宝小程序,确实,小程序的概念深入人心并且已经被约定俗成地绑定到某些互联网公司的App上。但是,“小程序”并不是一个注册商标,也不是哪一家的专利。小程序作为一种人机交互的软件载体、一种数字内容格式、一种代码分发传播机制,也到了被商业机构“借鉴”采用的时刻。企业们不是已经一直在用小程序吗?不算。因为他们不过是作为某个互联网大平台的内容贡献者、参与者,“免费”向互联网平台提供了自己的内容与服务,成为了别人的“生态一员”,换取流量的转化,以触达更多的互联网消费者。小程序类技术的企业商用,意味着:企业拥有了和互联网平台们类似的技术,能够以小程序这种技术载体、内容格式来开发自己的商业软件,从而享受这种技术带来的敏捷、轻量、极度松散耦合的好处。进一步,企业还能自主运营自己的平台,对其中小程序内容的上下架、审核发布完全掌握,让自己的业务功能灵活发表和投放;更进一步的,一些企业还可以开放自己的这种平台能力,让合作伙伴的小程序内容上架到平台上,以更好地服务自己的存量客户,建立行业数字生态,极大程度提升自己的数字化连接能力。新生物种:以小程序为载体的轻应用方案虽然互联网大厂并未将这部分小程序运行能力开放出来,但是我们也不必望而生羡,市面上早就推出了类似的技术能力,我们一般称之为小程序容器技术。今天要给大家分享的也正是国产自研发的前端容器技术
2023年5月24日
其他

我的新书冲到京东排行榜第一了

大家好,我是小风哥,今天再给大家宣布一个好消息,咱们的新书《计算机底层的秘密》冲到京东排行榜第一了,在这里真心感谢大家的支持。前天首发《十年所学终成一剑》后微信群里大家都开始晒单,大家的热情远超我的预料,再次感谢大家的支持。一直以来计算机书籍给人的感觉就和上学时一样:“团结、紧张、严肃”没有“活泼”,为什么读本书也要苦大仇深,不能好玩一些有趣一些吗?计算机系统到底是个什么东西?能不能不要填鸭般堆砌知识点,这些知识点的来龙去脉是什么?相互联系是什么?可不可以不要把我当硬盘直接往大脑里copy,能不能把这些知识点组织成有机的体系引导我一步步理解?可惜这些统统没有,你不得不自己去死磕,自己去感悟。这本书解决的就是这些痛点,所以我完全反着来。我会告诉你知识点的来龙去脉,我会告诉你知识点之间的联系是什么,我会从技术的本质出发一步步引导大家去理解,作为读者的你才是主角,我只是一个负责让你理解知识的配角,作为作者的我懂根本无关紧要,作为读者你能懂才是最重要的。我不会“紧张、严肃”一板一眼讲述各个章节,而是用了大量时间思考怎样通俗易懂、以大脑更容易接受的方式让你理解,一图胜千言,因此画了足足341精美插图辅助你理解,这个插图数量是我读过的任何一本技术书籍都没有的。现在《计算机底层的秘密》这本书正在热卖中,而且是五折,极为划算,下面是京东五折购买入口,大家火速下单啦!最后,再次感谢大家的支持,祝大家五一假期快乐!
2023年4月28日
其他

十年所学终成一剑,新书上市啦!

大家好,我是小风哥,今天隆重宣布一个好消息,我们的新书《计算机底层的秘密》终!于!上!市!啦。今天新书正式首发,全彩印刷,阅读体验值拉满,咱们公众号的读者直接是最低的5折!!!最重要的是,首批会有2000本签名版,想要签名版的同学可以先直接拉到文末二维码下单,手慢就没有啦。签名版中的100本还有我写的一句话,除此之外签名版中还有惊喜彩蛋等着大家(后续会揭晓谜底),数量有限速速下单,先拉到最后锁单然后再回来看。这是这本书诞生的地方——我的一方小书桌和陪伴多年的电脑。这两年基本上把所有业余时间都用在写文章上了,其中的艰辛与枯燥只有自己知道,但当书出来的那一刻什么都是值得的。这本书起源自己的疑问:我的代码看上去能正常运行,可这是为什么呢?程序到底是怎么运行起来的?计算机执行我的代码时底层发生了什么?CPU执行的这行代码会对计算机系统产生什么影响?没有人告诉我答案,现代计算机系统像汉堡包一样被层层抽象,程序员在上层编程时看不到底层细节,这提高了开发效率,然而我却对自己写的代码非常没有底气,原因就在于我不知道自己写的代码对计算机到底有什么影响。于是我下定决心死磕到底,一定要弄清楚这一切,这个过程并不轻松,各大部头书籍让人望而却步,技术讲解晦涩难懂,但每一次“哦,原来是这样呀!”的顿悟都是值得的,我想大家可能都会有这样的疑惑,于是我刻意收集所思所想才凝聚了这本书,相信你在看这本书时会有很多“原来是这样呀”时刻。我把部分文章发到了公众号里,收到了很多小伙伴的反馈:这更加坚定了出书的信心,能帮到大家一点真心感到高兴。这本书行文通俗易懂,之前看的好多技术书总感觉怕读者能看明白似的,但小风哥不一样,我最怕的就是你看不懂,各种类比用上,各种例子举起来,一图胜千言,所以我在这本书里画了足足341副精美插图,整书全图解,做到了一页一图。并且这本书绝不是单纯的知识点罗列与灌输,而是成体系的从技术的本质与起源出发一步步引导大家去理解,从而形成自己的体系,只有内化为自己认知里的知识才是知识,这本书让你能看懂能消化。而且这本书是全彩印刷,再加上大量的插图与精致排版,整书阅读体验非常棒,大家可以感受一下:下面是京东的五折签名版购买入口,大家火速下单啦!最后感谢我的公众号读者,没有你们就没有这本书,你们的一路陪伴是我人生中一段非常美好的经历,你们的支持永远是我写下去的最大动力。
2023年4月26日
其他

如何在不加锁的情况下解决多线程问题?

free这两个概念,在此之前我们先从最简单的有锁编程开始。我们知道,多线程同时修改共享变量时会出现数据不一致的问题,比如多个线程同时对一个变量加1,假设count的初始值为0:int
2023年3月2日
其他

彻底理解动态规划:编辑距离

j);该函数表示从i到word1的末尾形成的字符串与从j从word2的末尾形成的字符串的编辑距离。因此如果调用该函数时我们应该这样使用:EditDistance(0,
2023年1月6日
其他

彻底理解动态规划:赚最多钱的兼职

大家好,我是小风哥,休息了将近一周后终于满血复活了,关于阳康的故事下篇再聊,今天主讲技术。这是动态规划主题的第二篇,本文的题目是赚最多钱的兼职。假设你是搞钱小能手,搬砖之余周末还想去兼职,现在有n份工作,每份工作的起始时间保存在数组startTime中、结束时间保存在数组endTime中、能获取的报酬保存在数组profit中,那么你该怎样挑选在时间上不冲突的减重工作从而获取最多的报酬,返回该报酬。注意,在这里数组startTime已经按照从小到大的顺序排好序。假定现在有5份工作,startTime
2022年12月29日
其他

阳了!我的实验失败了!

大家好,我是小风哥!就在一周前管控放开后意识到可能感染只是时间问题,我开始有意做一个实验,要在自己能做的最极致的情况下看能坚持到什么时候。先说一下我的通勤方式—地铁,我的通勤时间较长,单程大概有一个半小时左右,也就是说我会在密闭的较大人流的空间呆上一个半小时,在这段时间里尽量选择人少的车厢,全程佩戴N95口罩。来到公司后其它的都好说,主要就是不摘口罩,不摘口罩,你可能会问吃饭喝水怎么办呢,此时就没办法戴口罩了吧。很简单,和平时吃饭的小伙伴提前打好招呼,然后我就跑去外面空气通畅的地方独自吃饭,北京的冬天相对寒冷,尤其最近一周室外最高气温都在零度左右,在这样的环境里吃饭还是别有一番体验的,除了吃完之外喝水也是同样如此。有的同事说你这样还不如阳了呢,哈哈,喜欢较真的我还真就想知道在做到极致的情况下能不能躲过去真能成功的话把这些经验推广一下。除此之外,在公司按电梯按钮时坚持使用一层纸隔离开,随身备上一小瓶喷雾酒精,任何时候认为触碰可疑的东西对手进行消毒。就这样坚持了一周,身边的同事陆陆续续开始中招,而我则一周都很安全,上周五面对几乎空无一人的办公室我觉得实验可能会成功。
2022年12月20日
其他

彻底理解动态规划1:最长公共超序列

大家好,我是小风哥,今天这篇文章会开启动态规划这个主题,动态规划是算法中非常重要的思想之一。今天的题目是最短公共超序列,如果一个字符串s在删除某些字符后形成t,那么我们说s是t的超序列,现在给定两个字符串str1与str2,返回str1与str2的最长公共超序列,如果有多个的话返回任意一个即可。假设str1为"abac",str2为“cab”,那么这两个字符串的最短公共超序列是“cabac”;而如果str1为“bc”,str2为“cab”,那么最短公共超序列是“cabc”或者“bcab”。想一想该怎样解决问题。子问题与选择动态规划类问题的关键在于找出子问题以及子问题与原始问题的关联,要想找出子问题就需要知道每一步的选择是什么。在这个问题中如果str1=“abec”、str2=“aecd”,因为st1与str2的第一个字符相同,那么我们知道字符‘a’一定是最短公共超序列中的一个,这样str1就变为了“bec”,str2就变为了“ecd”,而这个问题本质上和原始问题没有区别,就这样我们找到了子问题。现在,str1=“bec”和str2=“ecd”的第一个字符不再相等该怎么办呢?很简单:超序列中包含str1的第一个字符,这样str1就变为了“ec”,str2依然是“ecd”,假设此时str1与str2的最短公共超序列为supers1超序列中包含str2的第一个字符,这样str1依然是“bec”,str2就变为了“cd”,假设此时str1与str2的最短公共超序列为supers2原始问题的最长公共超序列一定是supers1与supers2中最短的那一个。现在我们找到了原始问题与子问题的关联。状态空间树基于上述分析,我们可以很容易的画出这样的状态空间树:上图中每一个方框都代码一个子问题,如果某个子问题中的两个字符串的首字符不相等那么会衍生出两个新的的子问题,超序列要么使用str1的第一个字符,要么使用str2的第一个字符;而如果str1与str2的首字符相同,那么超序列中只需要新增该字符即可。该状态空间树的叶子节点为所有str1与str2都为空,此时经过从根节点到叶子结点一路的选择我们就得到了其对应的超序列,从上图看有两种最短公共超序列“bcab”与“cabc”,长度都是4。从这棵状态空间树中你可以轻易的看到原始问题是如何分解为子问题的以及如果利用子问题的解来构建原始问题的解。图中每个方框代表一个子问题,决定子问题的只有两个元素,str1与str2首字符的在各自对应字符串的起始位置i和j,因此我们定义递归函数scs(shortest
2022年12月11日
其他

内存竟被”无意“破坏,真相究竟如何?

大家好,我是小风哥。内存是C/C++程序员的好帮手,我们通常说C/C++程序性能更高其原因之一就在于可以自己来管理内存,然而计算机科学中没有任何一项技术可以包治百病,内存问题也给C/C++程序员带来无尽的烦恼。野指针、数组越界、错误的内存分配或者释放、多线程读写导致内存被破坏等等,这些都会导致某段内存中的数据被”无意“的破坏掉,这类bug通常很难定位,因为当程序开始表现异常时通常已经距离真正出问题的地方很远了,常用的程序调试方法往往很难排查此类问题。既然这类问题通常是由于内存的读写造成,那么如果要是某一段内存被修改或者读取时我们能观察到此事件就好了,幸运的是这类技术已经实现了。一段示例在GDB中你可以通过添加watchpoint来观察一段内存,这段内存被修改时程序将会停止,此时我们就能知道到底是哪行代码对该内存进行了修改,这功能是不是很强大。接下来我们用示例来讲解一下,有这样一段代码:#include
2022年11月25日
其他

有可能一人搞定CPU、操作系统、编译器吗?

大家好,我是小风哥。计算机是非常复杂的系统,涉及CPU、内存、编译器(编程语言)、操作系统等等,那么有没有可能一个人同时搞定整个计算机系统呢?答案是肯定的,而且是早在1976年就搞定了,从头到尾一人搞定整个计算机系统,包括硬件以及软件,这台计算机系统长这样:打造这台计算机的就是图片中右边这个家伙,天才工程师Steve
2022年11月9日
自由知乎 自由微博
其他

增加内存会让计算机变快吗?

大家好,我是小风哥,今天聊一个简单的问题,增加更多内存会让你的计算机速度变快吗?要想解答这个问题,我们需要知道cpu、内存与程序这几者的关联,实际上非常简单:首先,可执行程序存储在磁盘中(当然也可以是其它介质),可执行程序中实际上主要包含两部分内容:机器指令以及指令依赖的数据;程序运行时首先被加载(load)到内存中,被加载到内存中的程序摇身一变就成为了我们说的进程,当然,内存中还运行着另一种特殊的程序:操作系统。只有当CPU真正执行机器指令时相应的进程才开始运行,此时CPU不断的从内存中取出指令并执行指令,当然除了机器指令外还需要读取内存中的数据。可以看到,当程序运行时与CPU交互的是内存而不是磁盘,内存中存储指令和数据、而CPU使用指令和数据,因此从这个角度看这是一个类似生产者与消费者问题,内存就好比大厨、CPU好比食客,如果大厨上菜太慢那么食客就要挨饿。除此之外,操作系统对内存的使用也不可忽略。操作系统是如何利用内存的?为充分利用内存与磁盘资源,现代操作系统中有很多非常聪明的设计。由于CPU一次只能运行一个程序,即使在多核系统中一般来说同时存在的进程数远远多于核数,也就是说在某一个时刻并不是所有的程序都在运行,即使对正在运行的进程来说由于局部性原理的存在,进程地址空间中总会有一部分指令或者数据是暂时用不到的。基于这些,操作系统先驱们看到了可以充分利用内存的机会,我们可以将暂时用不到的指令或者数据放到磁盘上去(swap
2022年10月31日
其他

3000字 | 程序员应如何理解Reactor模式?

loop要做的事情非常简单,那就是接收用户请求,然后让handler,或者回调函数去处理,这里的handler或者回调函数就好比大厨张三和李四去,handler或者回调函数可以和event
2022年10月25日
其他

Linux 性能分析工具汇总

出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章。本文也可以作为检验基础知识的指标,另外文章涵盖了一个系统的方方面面。如果没有完善的计算机系统知识,网络知识和操作系统知识,文档中的工具,是不可能完全掌握的,另外对系统性能分析和优化是一个长期的系列。本文档主要是结合Linux
2022年10月17日
其他

字节一面:非递归手写快速排序

大家好,我是小风哥。今天给大家讲解一道非常有趣的算法面试题,以非递归的形式来写快速排序。其实这也可以衍生出更多同类问题,非递归二叉树的前序、中序、后序遍历等等,这些问题的背后的思想是一致的,那就是用栈来手动模拟递归调用。道理很简单有没有,一句话就能说清楚,但问题是你真的理解了吗?该怎样用栈来手动模拟递归调用呢?你的大脑在面对这个问题时有一个清晰的思路吗?别着急,我们先从最简单的快排开始。快排,quick
2022年10月10日
其他

为什么C++中有函数指针还需要std::function?

retq可以看到,编译好后的函数func位于地址0x400526这个地址,让我们记住这个地址。然后运行一下编译后生成的程序,想一想这段代码会输出什么呢?显然应该是func函数的在内存中的地址!$
2022年9月19日
其他

为什么你迟迟不肯行动?

大家好,我是小风哥,大家中秋假期快乐。今天我们不聊技术,聊点轻松的话题,这也是我最近一直在思考的:为什么开始行动这么难?是啊,明明想完成一件事,比如跑步、学一门新的技术、尝试一下其它行业、写一篇文章等等这么难呢?迟迟不肯启动呢?我对这个问题有这样几点思考,欢迎大家评论区留言。巨大的惯性与不确定性个人感觉人生轨迹就犹如高速上负重奔跑的货车,当我们来到舒适区后巨大的惯性会推着我们前行,然而当我们开始一项新的赛道后这辆大货车要从静止到高速运行,因此要想启动起来必然是很困难的,几乎每个人都会遇到,我们要接受这种现实。现在我们知道了,要想从静止开始拉动这辆大货车本身就很难,更难的是还有不确定性。你其实并不知道这个赛道到底怎样,面对不确定性时人天然会有逃避倾向,也就是不选择,然而不选择有时并不能解决问题,尤其是当你的原有赛道不足以支持你的人生目标时,逃避解决不了问题,而之所以不知道选择什么其实根本的原因在于不知道自己想要什么,如果你很清楚的话那么根本不存在这个问题,去执行就好了。然而大部分人其实不知道自己到底想从事什么,因此我们必须要多尝试,这可能是唯一的可行方法。短视与长期主义除此之外,人的本性还有短视、急功近利,一辆大货车从静止到高速运行时需要时间的,而人类的本性是急于看到结果,很难做到长期主义,为什么人很难做到长期主义呢?除了心理学给出的一系列理由之外我的思考这也可能是基因里带来的,在远古缺吃少穿危机四伏的环境下,吃饭生存等眼下的问题都保证不了你怎么让古人去规划五年甚至十年后的生活,远古时期那些长期主义者可能都已经饿死了,进化论筛选出来的都是短视人,然而这些问题在现代社会是不存在的。现代社会的竞争几乎已经摆脱了吃饭生存的低层次的竞争,今天的你不必担心明天没有饭吃没有水喝、可能会被狮子老虎吃掉等,但人类进入现代社会的时间与人类诞生至今的时间想必短的几乎可以忽略不计,因此我们的基因里根本就不存在长期主义,所以长期主义必然是反人性的。因此短视不是你我的问题,但我们必须知道这个问题,只有知道问题的存在才有可能去解决问题,因此在一件事上如果你暂时还看不到结果也不必急于否定,如果你认为自己的方向没有问题那么即使暂时没有看到成果也需要继续坚持。完美主义阻碍我们行动的另一个大敌就是完美主义,我们最常拒绝行动的一个理由就是条件不具备,然而上手就能做到100分几乎是不可能的事情,不要忘了你是新手,怎么可能一上来就能达到专业级别呢?那为什么很多人都有幻想完美主义呢?这也许是和我们的教育以及社会环境的有关,从小到大,不管是读书还是工作,外界都在给我们的一个信号:不要犯错,犯错是不好的。犯错的确是不好的,但犯错是通往成长的必经之路,犯错其实是一种反馈,告诉我们哪里做得不对,如果你不去实践不去犯错那么你根本就不知道自己的想法竟然原来是错误的,竟然是这么不靠谱,从这个角度讲多犯错、早犯错要比不犯错好,这其实也是反人性的。解决问题那么怎样才能解决这些问题呢?小步快跑,从最小的点开始以最小的代价开始闭环跑通并去验证,就好比我们写的demo程序,demo并不是最终需要交付的终版,而是一个极简的实验版本,然而就是这个实验版本就能解答我们很多问题,甚至是核心问题,在此基础之上我们否定这个方向又或者经过验证后开始不断添加新的功能,这样既能快速看到结果又能持续的迭代,短期主义结合长期主义,我们需要反人性,但有时我们也需要利用人性。好啦,这个话题就到这里,感兴趣的同学欢迎留言讨论。最后,我准备开通知识星球啦,鼓励大家在这里输出自己的深度、系统性的思考,沉淀出知识,我个人的力量毕竟有限,不可能把计算机中所有的主题都能系统性总结出来,但有了你们就不一样了。加入星球,你既可以选出成为和小风哥一样的输出者(写作),也可以只作为输入者(阅读),并努力进化成为我们希望的样子。
2022年9月12日
其他

神奇的Google二进制编解码技术:Protobuf

计算机网络编程中一个非常基本的问题:该怎样表示client与server之间交互的数据,在往下看之前先想一想这个问题。共识与协议这个问题可不像看上去的那样简单,因为client进程和server进程运行在不同的机器上,这些机器可能运行在不同的处理器平台、可能运行在不同的操作系统、可能是由不同的编程语言编写的,server要怎样才能识别出client发送的是什么数据呢?就像这样:client给server发送了一段数据:0101000100100001server怎么能知道该怎样“解读”这段数据呢?显然,client和server在发送数据之前必须首先达成某种关于怎样解读数据的共识,这就是所谓的协议。这里的协议可以是这样的:“将每8个比特为一个单位解释为无符号数字”,如果协议是这样的,那么server接收到这串二进制后就会将其解析为81(01010001)与33(00100001)。当然,这里的协议也可以是这样的:“将每8个比特为一个单位解释为ASCII字符”,那么server接收到这串二进制后就将其解析为“Q!”。可见,同样一串二进制在不同的“上下文/协议”下有完全不一样的解读,这也是为什么计算机明明只认知0和1但是却能处理非常复杂任务的根本原因,因为一切都可以编码为0和1,同样的我们也可以从0和1中解析出我们想要的信息,这就是所谓的编解码技术。实际上不止0和1,我们也可以将信息编码为摩斯密码(Morse
2022年9月5日
其他

CPU与GPU到底有什么区别?

大家好,我是小风哥,今天简单聊聊CPU与GPU。CPU的故事我们聊得比较多了,之前也发布过很多关于CPU的文章,因此这里重点聊聊GPU。教授
2022年8月25日
其他

C语言中的volatile到底有什么用?

大家好,我是小风哥。学C语言时有一个奇怪的关键字volatile,这到底有什么用呢?volatile与编译器首先来看这样一段代码:int
2022年7月29日
其他

拓扑排序与图遍历:安排课程

点击“小风算法”,选择“设为星标”大家好,我是小风哥,这是LeetCode刷题系列第10篇。今天的题目LeetCode第207号题目,安排课程,有numCourses个课程,并给定一个数组prerequisites,对于每一项prerequisites[i]
2022年7月28日
其他

多线程一定能优化程序性能吗?

大家好,我是小风哥。问:如果一个和尚挑水喝,两个和尚抬水喝,三个和尚没水喝,那么众人拾柴一定火焰高吗?多线程一定能提高程序性能吗?在计算机科学中,这个问题的标准答案是“it
2022年7月20日
其他

为什么用C语言编写操作系统?

大家好,我是小风哥。你有没有想过,为什么大部分操作系统都使用C语言来编写而不是其它语言呢?这篇文章给你答案。C语言在处理器界很受欢迎首先不得不说的是C语言真的非常简单,看看K&R经典的"The
2022年6月23日
其他

彻底理解操作系统:CPU与实模式

对于人类来说,我们不喜欢拐弯抹角,喜欢更直接的东西,“有话直说”、“没有中间商赚差价”、“简洁的设计”等等,然而对于计算机,尤其是对内存管理来说则恰恰相反,在这里"简洁"的设计往往不是好的设计,这到底是什么意思呢?我们在很早的文章中就提到过,内存从本质上将非常简单,你可以将其想像成一个个的小盒子组成,每个小盒子要么能存储1要么存储0,每8个小盒子组成一个字节(8比特),每个字节都有一个唯一的地址,通过这个地址我们就能从相应的一组小盒子取出这个比特。其它没了。看到了吧,内存本身其实是非常简单的,然而程序员以及程序使用内存的方式又让这个问题变得复杂起来,分析任何复杂问题都要抓住重点、抓住核心问题,那么这里的重点以及核心是什么呢?不卖关子,这里的核心在于两个字:寻址,Addressing。一切都是围绕寻址展开的。寻址,最重要的就是寻址什么是寻址
2022年6月1日
其他

进程切换的本质是什么?

大家好,我是小风哥。我们都知道操作系统最重要的功能之一是多任务能力,也就是可以运行超过CPU数量的程序——即进程,要想实现这一功能就必须具备将有限的CPU资源在多个进程之间分配的能力,在程序员看来,我们的程序在一直运行,而在CPU看来程序其实在“走走停停”,程序的一走一停就涉及到进程切换,那么进程切换的本质是什么呢?从本质上讲,函数调用和进程切换是非常类似的,有的同学可能会有疑问,这怎么可能呢?别着急,看完这篇你就明白啦。函数调用我们先来看一下函数调用,函数调用是这样的,A函数调用B函数,当B函数执行完成时会跳转回A函数(此时A函数和B函数位于同一个进程):void
2022年4月28日
其他

stack vs heap:栈区分配内存快还是堆区分配内存快 ?

大家好,我是小风哥。后台有读者问到底是从栈上分配内存快还是从堆上分配内存快,这是个比较基础的问题,今天就来聊一聊。栈区的内存申请与释放毫无疑问,显然从栈上分配内存更快,因为从栈上分配内存仅仅就是栈指针的移动而已,这是什么意思呢?什么叫做“栈指针的移动”?以x86平台为例,在栈上分配内存是怎样实现的呢?很简单,就一行指令:sub
2022年3月16日
其他

操作系统是如何启动起来的?

loader功能更为丰富,比如对硬件进行检查、给用户提供选项加载哪个操作系统等等,安装多系统的同学应该知道,启动时会给你一个选项到底是启动windows还是linux,这就是二阶boot
2022年2月24日
其他

14万字,《计算机底层的秘密》免费下载

作为程序员你身边肯定有这样人:不管开发什么系统、遇到什么问题他都能快速抓住问题的本质,你一两天才能解决的问题他几乎能脱口而出给你答案,这些周围人眼中的大神就是所谓的10倍程序员。10倍程序员很重要的一个标识在于他们彻底掌握了计算机底层技术,可以毫不夸张的说他们甚至知道自己写下的每一行代码都是怎么被计算机执行的,这种对计算机系统底层技术强大的掌控力使得他们脱颖而出。而我的文章就全部围绕着底层这一要点展开,以图解的方式讲述比如进程、线程、协程、异步编程、高并发I/O、内存管理、操作系统、CPU等核心技术。有很多知乎朋友问有没有pdf版本,我也整理出来了,共14万字,绘图非常精美,这里还汇总了部分知乎问题,我为其专门设计了封面,并将其命名为《计算机底层的秘密》,现在免费分享给大家。获取方式:扫描下方二维码,关注我的公众号:码农的荒岛求生,关注后回复「底层」二字即可直接获得下载链接。也可以截图当前二维码后,微信扫码关注并回复「底层」
2022年1月15日
其他

彻底理解 C 语言中的指针

大家好,我是小风哥。假定给你一块非常小的内存,这块内存只有8字节,这里也没有高级语言,没有操作系统,你操作的数据单位是单个字节,你该怎样读写这块内存呢?注意这里的限定,再读一遍,没有高级语言,没有操作系统,在这样的限制之下,你必须直面内存读写的本质。这个本质是什么呢?本质是你需要意识到内存就是一个一个装有字节的小盒子,这些小盒子从0到N编好了序号。这时如果你想计算1+2,那么你必须先把1和2分别放到两个小盒子中,假设我们使用Store指令,把数字1放到第6号小盒子,那么用指令表示就是这样:store
2021年12月6日
其他

回调函数 callback 的实现原理是什么?

大家好,我是小风哥。在讲正文前闲聊几句,最近实在是有点忙,昨天已经是近期第二次通宵加班了,之前加班发到朋友圈后收到了很多同学的关心,很是感动,感谢大家:公司忙起来后的确有时加班挺狠的,但这不是常态,在这里也提醒大家千万不要熬夜,对身体健康真的不好,能不加班就不加班,早睡早起,身体是一切的基础。其实之前小风哥写过关于回调函数原理的文章,在这里《10张图让你彻底理解回调函数》,这篇文章内容很全面,但还是有很多同学在微信上问我有没有简化版的,以下就是回调函数原理的极简版。其实回调函数和普通函数没有本质的区别。首先让我们来看看普通的函数调用,假设我们在A函数中调用函数func:void
2021年10月22日
其他

看完这篇还不懂链表你来打我

};那么node里的内容应该是什么呢?很显然,有这节车厢装载的货物有没有,我们将其称作loads,类型是什么呢,这个其实是无所谓的,简单起见,我们就用int来表示:struct
2021年9月6日
其他

mmap可以让程序员解锁哪些骚操作?

大家好,我是小风哥!今天这篇文章带你讲解下稍显神秘的mmap到底是怎么一回事。简单的与麻烦的用代码读写内存对程序员来说是非常方便非常自然的,但用代码读写磁盘对程序员来说就不那么方便不那么自然了。回想一下,你在代码中读写内存有多简单:定义一个数组:int
2021年8月23日
其他

字节终面:CPU 是如何读写内存的?

如果你觉得这是一个非常简单的问题,那么你真应该好好读读本文,我敢保证这个问题绝没有你想象的那么简单。注意,一定要完本文,否则可能会得出错误的结论。闲话少说,让我们来看看CPU在读写内存时底层究竟发生了什么。谁来告诉CPU读写内存我们第一个要搞清楚的问题是:谁来告诉CPU去读写内存?答案很明显,是程序员,更具体的是编译器。CPU只是按照指令按部就班的执行,机器指令从哪里来的呢?是编译器生成的,程序员通过高级语言编写程序,编译器将其翻译为机器指令,机器指令来告诉CPU去读写内存。在精简指令集架构下会有特定的机器指令,Load/Store指令来读写内存,以x86为代表的复杂指令集架构下没有特定的访存指令。精简指令集下,一条机器指令操作的数据必须来存放在寄存器中,不能直接操作内存数据,因此RISC下,数据必须先从内存搬运到寄存器,这就是为什么RISC下会有特定的Load/Store访存指令,明白了吧。而x86下无此限制,一条机器指令操作的数据可以来自于寄存器也可以来自内存,因此这样一条机器指令在执行过程中会首先从内存中读取数据。关于复杂指令集以及精简指令集你可以参考这两篇文章《CPU进化论:复杂指令集》与《不懂精简指令集还敢说自己是程序员?》两种内存读写现在我们知道了,是特定的机器指令告诉CPU要去访问内存。不过,值得注意的是,不管是RISC下特定的Load/Store指令还是x86下包含在一条指令内部的访存操作,这里读写的都是内存中的数据,除此之外还要意识到,CPU除了从内存中读写数据外,还要从内存中读取下一条要执行的机器指令。毕竟,我们的计算设备都遵从冯诺依曼架构:程序和数据一视同仁,都可以存放在内存中。现在,我们清楚了CPU读写内存其实是由两个因素来驱动的:程序执行过程中需要读写来自内存中的数据CPU需要访问内存读取下一条要执行的机器指令然后CPU根据机器指令中包含的内存地址或者PC寄存器中下一条机器指令的地址访问内存。这不就完了吗?有了内存地址,CPU利用硬件通路直接读内存就好了,你可能也是这样的想的。真的是这样吗?别着急,我们接着往下看,这两节只是开胃菜,正餐才刚刚开始。急性子吃货
2021年7月5日
其他

不懂精简指令集还敢说自己是程序员?

在上一篇文章《CPU进化论:复杂指令集》中我们从历史的角度讲述了复杂指令集出现的必然,随着时间的推移,采用复杂指令集架构的CPU出现各种各样的问题,面对这些问题一部分人开始重新思考指令集到底该如何设计。在这一时期,两个趋势的出现促成一种新的指令集设计思想。内存与编译器时间来到了1980s年代,此时容量“高达”64K的内存开始出现,内存容量上终于不再捉襟见肘,价格也开始急速下降,在1977年,1MB内存的价格高达$5000,要知道这可是1977年的5000刀,但到了1994年,1MB内存价格就急速下降到大概只有$6,这是第一个趋势。此外在这一时期随着编译技术的进步,编译器越来越成熟,渐渐的程序员们开始依靠编译器来生成汇编指令而不再自己手工编写。这两个趋势的出现让人们有了更多思考。化繁为简19世纪末20世纪初意大利经济学家Pareto发现,在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%尽管是多数,却是次要的,这就是著名的二八定律,机器指令的执行频率也有类似的规律。大概80%的时间CPU都在执行那20%的机器指令,同时CISC中一部分比较复杂的指令并不怎么被经常用到,而且那些设计编译器的程序员也更倾向于组合一些简单的指令来完成特定任务。与此同时我们在上文提到过的一位计算机科学家,被派去改善微代码设计,但后来这老哥发现有问题的是微代码本身,因此开始转过头来去思考微代码这种设计的问题在哪里。他的早期工作提出一个关键点,复杂指令集中那些被认为可以提高性能的指令其实在内部被微代码拖后腿了,如果移除掉微代码,程序反而可以运行的更快,并且可以节省构造CPU消耗的晶体管数量。由于微代码的设计思想是将复杂机器指令在CPU内部转为相对简单的机器指令,这一过程对编译器不可见,也就是说你没有办法通过编译器去影响CPU内部的微代码运行行为,因此如果微代码出现bug那么编译器是无能为力的,你没有办法通过编译器生成其它机器指令来修复问题而只能去修改微代码本身。此外他还发现,有时一些复杂的机器指令执行起来要比等价的多个简单指令要。这一切都在提示:为什么不直接用一些简单到指令来替换掉那些复杂的指令呢?精简指令集哲学基于对复杂指令集的思考,精简指令集哲学诞生了,精简指令集主要体现在以下三个方面:1,指令本身的复杂度精简指令集的思想其实很简单,干嘛要去死磕复杂的指令,去掉复杂指令代之以一些简单的指令。有了简单指令CPU内部的微代码也不需要了,没有了微代码这层中间抽象,编译器生成的机器指令对CPU的控制力大大增强,有什么问题让写编译器的那帮家伙修复就好了,显然调试编译器这种软件要比调试CPU这种硬件要简单很多。注意,精简指令集思想不是说指令集中指令的数量变少,而是说一条指令背后代表的动作更简单了。举个简单的例子,复杂指令集中的一条指令背后代表的含义是“吃饭”的全部过程,而精简指令集中的一条指令仅仅表示“咀嚼一下”的其中一个小步骤。博主在《你管这破玩意叫编程语言》一文中举得例子其实更形象一些,复杂指令集下一条指令可以表示“给我端杯水”,而在精简指令集下你需要这样表示:2,编译器精简指令集的另一个特点就是编译器对CPU的控制力更强。在复杂指令集下,CPU会对编译器隐藏机器指令的执行细节,就像微代码一样,编译器对此无能为力。而在精简指令集下CPU内部的操作细节暴露给编译器,编译器可以对其进行控制,也因此,精简指令集RISC还有一个有趣的称呼:“Relegate
2021年6月7日
其他

CPU 进化论:复杂指令集 CISC

处理器就采用该设计,其中三分之一的晶体管都用在了微代码上。同年,计算机科学家Dave
2021年5月27日
其他

你管这破玩意叫 CPU ?

说:“我可以炒股”,你告诉CPU快滚一边去吧韭菜。因此我们可以看到CPU只提供机制或者说功能(打人、唱歌、炒菜,加法、减法、跳转),我们提供策略(打谁、歌名、菜名,操作数,跳转地址)。CPU
2021年4月26日
其他

特斯拉遇上 CPU:程序员的心思你别猜

18世纪流水线的诞生带来了制造技术的变革,人类当今拥有琳琅满目物美价廉的商品和流水线技术的发明密不可分,因此当你喝着可乐、吹着空调、坐在特斯拉里拿着智能手机刷这篇文章时需要感谢流水线技术。一段有趣的代码有这样一段代码:for
2021年4月8日
其他

假如你来发明编程语言

知道,心想“这就简直就是世界上最美的语言”。天降大任终于有一天程序员受够了说鸟语,好歹也是灵长类,叽叽喳喳说鸟语太没面子,你被委以重任:让程序员说人话。你没有苦其心志劳其筋骨,而是仔细研究了一下
2021年3月25日
其他

18张图揭秘高性能Linux服务器内存池技术是如何实现的

大家生活中肯定都有这样的经验,那就是大众化的产品都比较便宜,但便宜的大众产品就是一个词,普通;而可以定制的产品一般都价位不凡,这种定制的产品注定不会在大众中普及,因此定制产品就是一个词,独特。有的同学可能会有疑问,你不是要聊技术吗?怎么又说起消费了?原来技术也有大众货以及定制品。通用
2021年1月27日
其他

神秘!申请内存时底层发生了什么?

内存的申请释放对程序员来说就像空气一样自然,你几乎不怎么能意识到,有时你意识不到的东西却无比重要,申请过这么多内存,你知道申请内存时底层都发生什么了吗?大家都喜欢听故事,我们就从神话故事开始吧。三界中国古代的神话故事通常有“三界”之说,一般指的是天、地、人三界,天界是神仙所在的地方,凡人无法企及;人界说的是就是人间;地界说的是阎罗王所在的地方,孙悟空上天入地无所不能就是说可以在这三界自由出入。有的同学可能会问,这和计算机有什么关系呢?原来,我们的代码也是分三六九等的,程序运行起来后也是有“三界”之说的,程序运行起来的“三界”就是这样的:x86
2021年1月18日
其他

自己动手实现一个malloc内存分配器 | 30图

对内存分配器透彻理解是编程高手的标志之一。如果你不能理解malloc之类内存分配器实现原理的话,那你可能写不出高性能程序,写不出高性能程序就很难参与核心项目,参与不了核心项目那么很难升职加薪,很难升级加薪就无法走向人生巅峰,没想到内存分配竟如此关键,为了走上人生巅峰你也要势必读完本文。现在我们知道了,对内存分配器透彻的理解是写出高性能程序的关键所在,那么我们该怎样透彻理解内存分配器呢?还有什么能比你自己动手实现一个理解的更透彻吗?接下来,我们就自己实现一个malloc内存分配器。读完本文后内存分配对你将不再是一个神秘的黑盒。在讲解实现原理之前,我们需要回答一个基本问题,那就是我们为什么要发明内存分配器这种东西。内存申请与释放程序员经常使用的内存申请方式被称为动态内存分配,Dynamic
2021年1月6日
其他

线程安全代码到底是怎么编写的?

相信有很多同学在面对多线程代码时都会望而生畏,认为多线程代码就像一头难以驯服的怪兽,你制服不了这头怪兽它就会反过来吞噬你。夸张了哈,总之,多线程程序有时就像一潭淤泥,走不进去退不出来。可这是为什么呢?为什么多线程代码如此难以正确编写呢?从根源上思考关于这个问题,本质上是有一个词语你没有透彻理解,这个词就是所谓的线程安全,thread
2020年12月28日
其他

线程间到底共享了哪些进程资源?

进程和线程这两个话题是程序员绕不开的,操作系统提供的这两个抽象概念实在是太重要了。关于进程和线程有一个极其经典的问题,那就是进程和线程的区别是什么?相信很多同学对答案似懂非懂。记住了不一定真懂关于这个问题有的同学可能已经“背得”滚瓜烂熟了:“进程是操作系统分配资源的单位,线程是调度的基本单位,线程之间共享进程资源”。可是你真的理解了上面最后一句话吗?到底线程之间共享了哪些进程资源,共享资源意味着什么?共享资源这种机制是如何实现的?对此如果你没有答案的话,那么这意味着你几乎很难写出能正确工作的多线程程序,同时也意味着这篇文章就是为你准备的。逆向思考查理芒格经常说这样一句话:“反过来想,总是反过来想”,如果你对线程之间共享了哪些进程资源这个问题想不清楚的话那么也可以反过来思考,那就是有哪些资源是线程私有的。
2020年12月14日
其他

程序员应如何理解高并发中的协程

作为程序员,想必你多多少少听过协程这个词,这项技术近年来越来越多的出现在程序员的视野当中,尤其高性能高并发领域。当你的同学、同事提到协程时如果你的大脑一片空白,对其毫无概念。。。那么这篇文章正是为你量身打造的。话不多说,今天的主题就是作为程序员,你应该如何彻底理解协程。普通的函数我们先来看一个普通的函数,这个函数非常简单:def
2020年11月30日
其他

函数运行时在内存中是什么样子?

我们在上一篇文章《高性能高并发服务器是如何实现的》中提到了一项关键技术——协程,你知道协程的本质是什么吗?有的同学可能会说是用户态线程,那么什么是用户态线程,这是怎么实现的?3.
2020年11月16日
其他

高并发高性能服务器是如何实现的

当在读这篇文章的时候,你有没有想过,服务器是怎么把这篇文章发送给你的呢?说简单也简单,不就是一个用户请求吗?服务器根据请求从数据库中捞出这篇文章,然后通过网络发回去。说复杂也复杂,服务器是如何并行处理成千上万个用户请求呢?这里面涉及到哪些技术呢?这篇文章就来为你解答这个问题。多进程历史上最早出现也是最简单的一种并行处理多个请求的方法就是利用多进程。比如在Linux世界中,我们可以使用fork、exec等系统调用创建多个进程,我们可以在父进程中接收用户的连接请求,然后创建子进程去处理用户请求,就像这样:这种方法的优点就在于:编程简单,非常容易理解由于各个进程的地址空间是相互隔离的,因此一个进程崩溃后并不会影响其它进程充分利用多核资源多进程并行处理的优点很明显,但是缺点同样明显:各个进程地址空间相互隔离,这一优点也会变成缺点,那就是进程间要想通信就会变得比较困难,你需要借助进程间通信(IPC,interprocess
2020年11月9日
其他

10张图让你彻底理解回调函数

不知你是不是也有这样的疑惑,我们为什么需要回调函数这个概念呢?直接调用函数不就可以了?回调函数到底有什么作用?程序员到底该如何理解回调函数?这篇文章就来为你解答这些问题,读完这篇文章后你的武器库将新增一件功能强大的利器。一切要从这样的需求说起假设你们公司要开发下一代国民App“明日油条”,一款主打解决国民早餐问题的App,为了加快开发进度,这款应用由A小组和B小组协同开发。其中有一个核心模块由A小组开发然后供B小组调用,这个核心模块被封装成了一个函数,这个函数就叫make_youtiao()。如果make_youtiao()这个函数执行的很快并可以立即返回,那么B小组的同学只需要:调用make_youtiao()等待该函数执行完成该函数执行完后继续后续流程从程序执行的角度看这个过程是这样的:保存当前被执行函数的上下文开始执行make_youtiao()这个函数make_youtiao()执行完后,控制转回到调用函数中如果世界上所有的函数都像make_youtiao()这么简单,那么程序员大概率就要失业了,还好程序的世界是复杂的,这样程序员才有了存在的价值。现实并不容易现实中make_youtiao()这个函数需要处理的数据非常庞大,假设有10000个,那么make_youtiao(10000)不会立刻返回,而是可能需要10分钟才执行完成并返回。这时你该怎么办呢?想一想这个问题。可能有的同学会问,和刚才一样直接调用不可以吗,这样多简单。是的,这样做没有问题,但就像爱因斯坦说的那样“一切都应该尽可能简单,但是不能过于简单”。想一想直接调用会有什么问题?显然直接调用的话,那么调用线程会被阻塞暂停,在等待10分钟后才能继续运行。在这10分钟内该线程不会被操作系统分配CPU,也就是说该线程得不到任何推进。这并不是一种高效的做法。没有一个程序员想死盯着屏幕10分钟后才能得到结果。那么有没有一种更加高效的做法呢?想一想我们上一篇中那个一直盯着你写代码的老板(见《从小白到高手,你需要理解同步与异步》),我们已经知道了这种一直等待直到另一个任务完成的模式叫做同步。如果你是老板的话你会什么都不干一直盯着员工写代码吗?因此一种更好的做法是程序员在代码的时候老板该干啥干啥,程序员写完后自然会通知老板,这样老板和程序员都不需要相互等待,这种模式被称为异步。回到我们的主题,这里一种更好的方式是调用make_youtiao()这个函数后不再等待这个函数执行完成,而是直接返回继续后续流程,这样A小组的程序就可以和make_youtiao()这个函数同时进行了,就像这样:在这种情况下,回调(callback)就必须出场了。为什么我们需要回调callback有的同学可能还没有明白为什么在这种情况下需要回调,别着急,我们慢慢讲。假设我们“明日油条”App代码第一版是这样写的:make_youtiao(10000);sell();可以看到这是最简单的写法,意思很简单,制作好油条后卖出去。我们已经知道了由于make_youtiao(10000)这个函数10分钟才能返回,你不想一直死盯着屏幕10分钟等待结果,那么一种更好的方法是让make_youtiao()这个函数知道制作完油条后该干什么,即,更好的调用make_youtiao的方式是这样的:“制作10000个油条,炸好后卖出去”,因此调用make_youtiao就变出这样了:make_youtiao(10000,
2020年10月28日
其他

从小白到高手,你需要理解同步与异步(内含10张图)

承接上文《终于明白了,一文彻底理解I/O多路复用》。在这篇文章中我们来讨论一下到底什么是同步,什么是异步,以及在编程中这两个极为重要的概念到底意味着什么。相信很多同学遇到同步异步这两个词的时候大脑瞬间就像红绿灯失灵的十字路口一样陷入一片懵逼的状态:是的,这两个看上去很像实际上也很像的词汇给博主造成过很大的困扰,这两个词背后所代表的含义到底是什么呢?我们先从工作场景讲起。苦逼程序员假设现在老板分配给了你一个很紧急并且很重要的任务,让你下班前必须完成(万恶的资本主义)。为了督促进度,老板搬了个椅子坐在一边盯着你写代码。你心里肯定已经骂上了,“WTF,你有这么闲吗?盯着老子,你就不能去干点其他事情吗?”老板仿佛接收到了你的脑电波一样:“我就在这等着,你写完前我哪也不去,厕所也不去。”这个例子中老板交给你任务后就一直等待,什么都不做直到你写完,这个场景就是所谓的同步。第二天,老板又交给了你一项任务。不过这次就没那么着急啦,这次老板轻描淡写,“小伙子可以啊,不错不错,你再努力干一年,明年我就财务自由了,今天的这个任务不着急,你写完告诉我一声就行”。这次老板没有盯着你写代码,而是转身刷视频去了,你写完后简单的和老板报告一声“我写完了”。在这个例子中老板交代完任务后不再一直等着什么都不做而是就去忙其它事情,你完成任务后简单的告诉老板任务完成,这就是所谓的异步。值得注意的是,在异步这种场景下重点是在你写代码的同时老板在刷剧,这两件事在同时进行,而不是一方等待另一方,因此这就是为什么一般来说异步比同步高效的本质所在,不管同步异步应用在什么场景下。我们可以看到同步这个词往往和任务的“依赖”、“关联”、“等待”等关键词相关,而异步往往和任务的“不依赖”,“无关联”,“无需等待”,“同时发生”等关键词相关。By
2020年10月12日