这篇文章将会是一篇很长很长的文章,希望能将一点计算机科学课程的知识和开发用到的部分知识结合在一块。定位是普及知识的水平。

冯诺依曼结构

先从计算机的结构说起。今天的计算机几乎都是冯诺依曼架构,大概是这样:

冯诺依曼架构

输入设备举例:鼠标,键盘等,输出设备举例:显示屏。值得注意的是这里的存储器指的是内存,而不是硬盘。硬盘通常被叫做外部存储。任何程序(包括os内核)运行时必须先从外部存储设备加载到内存。这样看来,冯诺依曼结构实际上就是以CPU为核心,不断的从内存输入数据然后运算再写回内存(即IO操作)。

汇编-程序运行流程

汇编中告诉我们一个程序是这样运行的:从内存中读取汇编指令(所有的代码都要转换为汇编指令)到CPU中然后执行,周而复始。几乎所有的汇编指令都是进行一些运算或者是完成IO操作(即读写)。

操作系统&syscall

早期的计算机是没有操作系统的概念的。后来为了便于管理计算机的硬件资源(如内存,硬盘),提高效率等用途,才引入的。

操作系统(Operating System,简称OS)是管理[计算机硬件](https://baike.baidu.com/item/计算机硬件/5459592)与[软件](https://baike.baidu.com/item/软件/12053)资源的[计算机程序](https://baike.baidu.com/item/计算机程序/3220205)。操作系统需要处理如管理与配置[内存](https://baike.baidu.com/item/内存/103614)、决定[系统资源](https://baike.baidu.com/item/系统资源/974435)供需的优先次序、控制[输入设备](https://baike.baidu.com/item/输入设备/10823368)与[输出设备](https://baike.baidu.com/item/输出设备/10823333)、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。         -----百度百科

那么对于开发人员又是如何控制输入输出设备呢?由于硬件种类多样且操作复杂,因此通常将这一部分交由操作系统处理,而只对开发人员暴露完成指定功能的函数,这些函数我们称作系统调用(syscall)。开发人员可以通过直接调用操作系统提供的系统调用完成对硬件的控制。实际上我们在汇编程序设计中就是通过调用系统调用的方式来完成从键盘读取字符/在屏幕上显示(写出)字符等功能。正如你在汇编中的操作一样,调用系统调用的步骤是:

  1. 将需要调用的系统调用号放入指定寄存器
  2. 按照约定传递参数(即将参数放入寄存器或压栈等)
  3. 调用中断指令

值得注意的是,在不同的架构(如amd64,i386,arm)和操作系统下,调用syscall的步骤类似。但又有略区别。对于第一步中的系统调用号与对应的功能有相应的表格,我们称之为 sys(tem) call table。对于第二步的约定,我们通常称作调用规约,这个主要是由操作系统和架构决定(注意,调用非sys call也存在调用规约,但由于不和操作系统打交道,因此通常由编译器决定,例如有 stdcall,cdecl)。对于第三步所调用的中断指令与架构有关,不同的情况下使用的中断号可能不同。(同时,由于使用中断来完成syscall的方式存在性能问题并且调用syscall又比较频繁,因此后来的CPU和操作系统提供了另一种指令来替代)

除此之外,由于我们不能直接操作硬件设备,因此某种语言或框架是否具有某种能力(IO多路复用,异步IO,Zero Copy等),归根到底取决于我们的操作系统是否提供了相应的系统调用。(操作系统:我说行才行,我说不行就不行。)

tips:看到这里我希望大家能树立两个观念。1是CPU几乎所有的操作都是直接或者间接为了IO,因为只有通过IO才能完成与外界的交换。(试想:如果CPU运算出了结果却不能将结果反馈给你,那么还有意义吗,并且没了IO CPU也不知道要算什么东西啊。2是xx软件或者xx语言是否高效或者具有某种能力,归根到底看操作系统是否提供了相应的syscall。(这些能力指的一般是硬件相关的,因为用户态的软件基本无法直接操作硬件)

同步异步,阻塞非阻塞,JavaNIO,go,异步,协程等为何高效?

我们经常会看到这几个概念。它们是相似的但是却有所不同。我们在开发过程中,调用函数(包括syscall)是不可避免的。这些函数有些能立即返回(或者很快),有一些却需要时间(主要是IO操作类)。

  • 同步|异步

    同步/异步的概念是从函数的调用者的角度来说的,即我调用一个需要花费一些时间才能完成的函数时是否等待这个函数执行完毕再继续往下执行。如果等待为同步,如果不等待则为异步。

  • 阻塞|非阻塞

    阻塞非阻塞是从函数自身来说的,即别人调用我时我是否立即返回或者需要一些时间才能返回。如果立即返回则为非阻塞,如果需要较长的时间则为阻塞。

那么如何理解这个时间的长短呢?多少为短呢?

我们可以简单的认为无IO读写的操作可以看作立即返回。但并不是所有的IO操作一定是阻塞的。例如Linux下可以通过fcntl将一个fd(文件描述符)设置为非阻塞。此时调用[read](https://baike.baidu.com/item/read%28%29/9848648?fr=aladdin)/write操作此fd将立即返回(不能立即完成就立即返回一个error)。

未完待续…
接下来要讲的:
进程,线程

速度

Memory Hierarchy-计算机各级存储器速度对比_farmwang的专栏-CSDN博客

还有从rust2020conf中偷的两张图

从rust2020conf中偷的两张图:

rust中的异步