diff --git "a/3\343\200\201\345\257\271\344\272\216\346\223\215\344\275\234\347\263\273\347\273\237\350\200\214\350\250\200\350\277\233\347\250\213\343\200\201\347\272\277\347\250\213\344\273\245\345\217\212Goroutine\345\215\217\347\250\213\347\232\204\345\214\272\345\210\253.md" "b/3\343\200\201\345\257\271\344\272\216\346\223\215\344\275\234\347\263\273\347\273\237\350\200\214\350\250\200\350\277\233\347\250\213\343\200\201\347\272\277\347\250\213\344\273\245\345\217\212Goroutine\345\215\217\347\250\213\347\232\204\345\214\272\345\210\253.md" index 0ab031c..6a603fd 100644 --- "a/3\343\200\201\345\257\271\344\272\216\346\223\215\344\275\234\347\263\273\347\273\237\350\200\214\350\250\200\350\277\233\347\250\213\343\200\201\347\272\277\347\250\213\344\273\245\345\217\212Goroutine\345\215\217\347\250\213\347\232\204\345\214\272\345\210\253.md" +++ "b/3\343\200\201\345\257\271\344\272\216\346\223\215\344\275\234\347\263\273\347\273\237\350\200\214\350\250\200\350\277\233\347\250\213\343\200\201\347\272\277\347\250\213\344\273\245\345\217\212Goroutine\345\215\217\347\250\213\347\232\204\345\214\272\345\210\253.md" @@ -93,7 +93,7 @@ 协程切换比线程切换快主要有两点: -(1)协程切换**完全在用户空间进行**线程切换涉及**特权模式切换,需要在内核空间完成**; +(1)协程切换**完全在用户空间进行**。线程切换涉及**特权模式切换,需要在内核空间完成**; (2)协程切换相比线程切换**做的事情更少**,线程需要有内核和用户态的切换,系统调用过程。 @@ -101,13 +101,13 @@ #### 协程切换成本: -协程切换非常简单,就是把**当前协程的 CPU 寄存器状态保存起来,然后将需要切换进来的协程的 CPU 寄存器状态加载的 CPU 寄存器上**就 ok 了。而且**完全在用户态进行**,一般来说一次协程上下文切换最多就是**几十ns** 这个量级。 +协程切换非常简单,就是把**当前协程的 CPU 寄存器状态保存起来,然后将需要切换进来的协程的 CPU 寄存器状态加载到 CPU 寄存器上**就 ok 了。而且**完全在用户态进行**,一般来说一次协程上下文切换最多就是**几十ns** 这个量级。 #### 线程切换成本: -系统内核调度的对象是线程,因为线程是调度的基本单元(进程是资源拥有的基本单元,进程的切换需要做的事情更多,这里占时不讨论进程切换),而**线程的调度只有拥有最高权限的内核空间才可以完成**,所以线程的切换涉及到**用户空间和内核空间的切换**,也就是特权模式切换,然后需要操作系统调度模块完成**线程调度(task***struct),*而且除了和协程相同基本的 CPU 上下文,还有线程私有的栈和寄存器等,说白了就是上下文比协程多一些,其实简单比较下 task_strcut 和 任何一个协程库的 coroutine 的 struct 结构体大小就能明显区分出来。而且特权模式切换的开销确实不小,随便搜一组测试数据 [3],随便算算都比协程切换开销大很多。 +系统内核调度的对象是线程,因为线程是调度的基本单元(进程是资源拥有的基本单元,进程的切换需要做的事情更多,这里占时不讨论进程切换),而**线程的调度只有拥有最高权限的内核空间才可以完成**,所以线程的切换涉及到**用户空间和内核空间的切换**,也就是特权模式切换,然后需要操作系统调度模块完成**线程调度(task_struct)**,而且除了和协程相同基本的 CPU 上下文,还有线程私有的栈和寄存器等,说白了就是上下文比协程多一些,其实简单比较下 task_strcut 和 任何一个协程库的 coroutine 的 struct 结构体大小就能明显区分出来。而且特权模式切换的开销确实不小,随便搜一组测试数据 [3],随便算算都比协程切换开销大很多。 @@ -222,7 +222,7 @@ KiB Swap: 969960 total, 563688 free, 406272 used. 168812 avail Mem free的mem为1675844, -所以**20万个协程占用了约 50万KB****平均一个协程占用约2.5KB** +所以 **20万个** 协程占用了约 **50万KB**, **平均** 一个协程占用约 **2.5KB** diff --git "a/5\343\200\201channel.md" "b/5\343\200\201channel.md" index d581dd8..33cbb9f 100644 --- "a/5\343\200\201channel.md" +++ "b/5\343\200\201channel.md" @@ -12,14 +12,13 @@ * 给一个已经关闭的 channel 发送数据,引起 panic -* 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值 +* 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回 **一个零值 和 false** (ex: `val,ok:= <-ch1`) * 无缓冲的channel是同步的,而有缓冲的channel是非同步的 -以上5个特性是死东西,也可以通过口诀来记忆:“空读写阻塞,写关闭异常,读关闭空零”。 - - +以上5个特性是死东西,也可以通过口诀来记忆:“读写**空**阻塞,写**关闭**异常,读**关闭空**零假”。 +![](images/169-channel异常情况总结.png) > 执行下面的代码发生什么? @@ -59,7 +58,7 @@ func main() { -15字口诀:“空读写阻塞,写关闭异常,读关闭空零”,往已经关闭的channel写入数据会panic的。因为main在开辟完两个goroutine之后,立刻关闭了ch, 结果: +15字口诀:“读写**空**阻塞,写**关闭**异常,读**关闭空**零假”,往已经关闭的channel写入数据会panic的。因为main在开辟完两个goroutine之后,立刻关闭了ch, 结果: ``` panic: send on closed channel diff --git "a/images/169-channel\345\274\202\345\270\270\346\203\205\345\206\265\346\200\273\347\273\223.png" "b/images/169-channel\345\274\202\345\270\270\346\203\205\345\206\265\346\200\273\347\273\223.png" new file mode 100644 index 0000000..e7e56b8 Binary files /dev/null and "b/images/169-channel\345\274\202\345\270\270\346\203\205\345\206\265\346\200\273\347\273\223.png" differ