|
5 | 5 | > 消息的传递有可能是**阻塞的**或**非阻塞的**,也被称为**同步**或**异步**的。----《操作系统概论》
|
6 | 6 |
|
7 | 7 | - 阻塞式发送:blocking send,发送方进程会被一直阻塞,直到消息被接受方进程收到
|
8 |
| -- 非阻塞式发送:nonblocking send),发送方进程调用 send() 后,立即就可以其他操作 |
| 8 | +- 非阻塞式发送:nonblocking send,发送方进程调用 send() 后,立即就可以其他操作 |
9 | 9 | - 阻塞式接收:blocking receive,接收方调用 receive() 后一直阻塞,直到消息到达可用
|
10 | 10 | - 非阻塞式接受:nonblocking receive,接收方调用 receive() 函数后,要么得到一个有效的结果,要么得到一个空值,即不会被阻塞。
|
11 | 11 |
|
|
14 | 14 | 概念解释:
|
15 | 15 | - 中断(interrupt):CPU 微处理器有一个中断信号位, 在每个CPU时钟周期的末尾, CPU会去检测那个中断信号位是否有中断信号到达, 如果有,则会根据中断优先级决定是否要暂停当前执行的指令, 转而去执行处理中断的指令。 (其实就是 CPU 层级的 while 轮询)
|
16 | 16 | - 时钟中断( Clock Interrupt ):一个硬件时钟会每隔一段(很短)的时间就产生一个中断信号发送给 CPU,CPU 在响应这个中断时, 就会去执行操作系统内核的指令, 继而将 CPU 的控制权转移给了操作系统内核, 可以由操作系统内核决定下一个要被执行的指令。
|
17 |
| -- 系统调用(system call):system call 是操作系统提供给应用程序的接口。 用户通过调用 systemcall 来完成那些需要操作系统内核进行的操作, 例如硬盘, 网络接口设备的读写等。 |
| 17 | +- 系统调用(system call):system call 是操作系统提供给应用程序的接口。 用户通过调用 system call 来完成那些需要操作系统内核进行的操作, 例如硬盘, 网络接口设备的读写等。 |
18 | 18 |
|
19 |
| -进程在从用户空间切换到内核空间,需要以下步骤: |
| 19 | +现代操作系统都是采用虚拟存储器。操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。 |
| 20 | + |
| 21 | +用户进程在从用户空间切换到内核空间,需要以下步骤: |
20 | 22 | - 1.当一个程序正在执行的过程中, 中断(interrupt) 或 系统调用(system call) 发生可以使得 CPU 的控制权会从当前进程转移到操作系统内核。
|
21 | 23 | - 2.操作系统内核负责保存进程i在 CPU 中的上下文(程序计数器,寄存器)到 PCB$_i$(操作系统分配给进程的一个内存块)中
|
22 | 24 | - 3.从PCB$_j$取出进程 j 的CPU 上下文, 将 CPU 控制权转移给进程 j , 开始执行进程 j 的指令。
|
|
25 | 27 |
|
26 | 28 | 综上所述,**阻塞和非阻塞描述的是进程的一个操作是否会使得进程转变为“等待”的状态**,又因为阻塞这个词是与系统调用 System Call 紧紧联系在一起的, 因为要让一个进程进入 等待(waiting) 的状态,要么是它主动调用 wait() 或 sleep() 等挂起自己的操作,要么是它调用 System Call, 而 System Call 因为涉及到了 I/O 操作,不能立即完成,于是内核就会先将该进程置为等待状态,调度其他进程的运行,等到它所请求的 I/O 操作完成了以后,再将其状态更改回 ready 。
|
27 | 29 |
|
28 |
| -操作系统内核在执行 System Call 时, CPU 需要与 IO 设备完成一系列物理通信上的交互, 其实再一次会涉及到阻塞和非阻塞的问题, 例如, 操作系统发起了一个读硬盘的请求后, 其实是向硬盘设备通过总线发出了一个请求,它即可以阻塞式地等待IO 设备的返回结果,也可以非阻塞式的继续其他的操作。 在现代计算机中,这些物理通信操作基本都是异步完成的, 即发出请求后, 等待 I/O 设备的中断信号后, 再来读取相应的设备缓冲区。 但是,大部分操作系统默认为用户级应用程序提供的都是阻塞式的系统调用 (blocking systemcall)接口, 因为阻塞式的调用,使得应用级代码的编写更容易(代码的执!行顺序和编写顺序是一致的)。 |
| 30 | +操作系统内核在执行 System Call 时, CPU 需要与 IO 设备完成一系列物理通信上的交互, 其实会再一次涉及到阻塞和非阻塞的问题, 例如, 操作系统发起了一个硬盘读的请求后, 其实是通过总线向硬盘设备发出了一个读请求,它即可以阻塞式地等待IO 设备的返回结果,也可以非阻塞式的继续其他的操作。 在现代计算机中,这些物理通信操作基本都是异步完成的, 即发出请求后, 等待 I/O 设备的中断信号后, 再来读取相应的设备缓冲区。 但是,大部分操作系统默认为用户级应用程序提供的都是阻塞式的系统调用 (blocking system call)接口, 因为阻塞式的调用,使得应用级代码的编写更容易(代码的执行顺序和编写顺序是一致的)。 |
29 | 31 |
|
30 | 32 | 但同样,现在的大部分操作系统也会提供非阻塞I/O 系统调用接口(Nonblocking I/O system call)。 一个非阻塞调用不会挂起调用程序, 而是会立即返回一个值,表示有多少bytes 的数据被成功读取(或写入)。
|
31 | 33 |
|
@@ -107,7 +109,7 @@ Unix网络编程中,可以利用的IO模型有5种:
|
107 | 109 |
|
108 | 110 | ### 2.1 多进程
|
109 | 111 |
|
110 |
| -每到达一个请求, 们为这个请求新创建一个进程来处理。这样,一个进程在等待 IO 时,其他的进程可以被调度执行,更加充分地利用 CPU 等资源。但是每新创建一个进程都会消耗一定的内存空间,且进程切换也会有时间消耗,高并发时,大量进程来回切换的时间开销会变得明显起来。 |
| 112 | +每到达一个请求,我们为这个请求新创建一个进程来处理。这样,一个进程在等待 IO 时,其他的进程可以被调度执行,更加充分地利用 CPU 等资源。但是每新创建一个进程都会消耗一定的内存空间,且进程切换也有时间消耗,高并发时,大量进程来回切换的时间开销会变得明显起来。 |
111 | 113 |
|
112 | 114 | ### 2.2 多线程模式
|
113 | 115 |
|
@@ -168,4 +170,4 @@ Node中的事件驱动:Event Loop is a programming construct that waits for an
|
168 | 170 | - 1、每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)。
|
169 | 171 | - 2、主线程之外,还维护了一个"事件队列"(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。
|
170 | 172 | - 3、主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。
|
171 |
| -- 4、主线程不断重复上面的第三步。 |
| 173 | +- 4、主线程不断重复上面的第三步。 |
0 commit comments