ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 进程 ![](http://cdn.aipin100.cn/17-10-9/66029542.jpg) ### 进程是什么? 如果你搜索“什么是进程?”,你大概都会看到这样的答案:“进程是程序的基本执行实体”,“进程是系统进行资源分配和调度的基本单位”,...等等。 看了后你还是不懂什么是进程,因为这个回答太官方了,除了让你不明觉厉之外没有作用。 那为什么进程的概念很难说清楚呢,或者说为什么向人描述清楚“进程是什么?”的这个问题不容易呢。 这要从我们写的代码是怎么在计算机中被执行的说起了,并不是像我们想象中的那样,自上而下,独占CPU,整体一遍过执行完的,真实的代码变成指令,再被调度执行很复杂,这里只做一个引子,感兴趣的读者可以自行查阅[相关资料](https://mp.weixin.qq.com/s/Q0SaoTg9GTXwOeh0GmLOuQ)。 代码的真实执行过程不是我们所想象的那样,但是程序员喜欢简单,不想关心底层复杂的具体执行,毕竟写上层业务功能就已经不容易了。于是操作系统就满足了程序员这个愿望,满足的方式就是创建了进程的概念给程序员理解,屏蔽掉其它复杂的概念。 这就是进程。 等等,我好像还没有说“进程是什么”。 但我想你已经明白了,你会有自己的思考和理解,可能每个人理解都会不一样,可至少对于这个问题你已经有了自己的思考,不会再只有不明觉厉。 ---- ### 进程的概念 进程:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位。 更多的信息需要你自行搜索相关资料以加深理解,详细讲解进程的概念不在本文的范畴内。 php的进程操作需要安装 [pcntl](http://php.net/manual/zh/book.pcntl.php) 扩展。 [操作系统 - 进程的概念 - 情有独钟 - 博客园](https://www.cnblogs.com/tianlangshu/p/5224178.html) [编程这么久你可能没真正了解进程](https://mp.weixin.qq.com/s/FRwg2WPbYkdnN71dCGPe6w) [高并发的那点事儿](https://mp.weixin.qq.com/s/n9FnQq2K93JTTr1kMkwJaw) ***** ### 多进程 在php中使用 [pcntl_fork](http://php.net/manual/zh/function.pcntl-fork.php) 函数创建进程。 从官方文档的介绍中,我们总结出`pcntl_fork()`有以下几点重要的特性: 1. 从当前进程`pcntl_fork()`调用的位置处产生分支(子进程) 2. **父进程和子进程 都从fork的位置开始向下继续执行**,不同的是父进程执行过程中,得到的fork返回值为子进程的进程id,而子进程得到的是0。 3. 返回值:成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。**根据返回值我们就知道父进程与子进程的代码部分。** 4. 子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。**子进程拥有父进程完整的副本(函数、变量等),而不是共享,进程间相互独立,互不影响**,每次fork都将**以当前环境产生新的副本。** 5. fork之后,是父进程先执行还是子进程先执行无法确认,准确的说是,**进程的执行顺序不受控制,而是取决于系统调度。** 6. **在跳转分支结构中,子进程可能会出现“往回执行”的情况**,此时应特别注意。通常出现此问题是由于子进程没有退出的原因造成的。 如果你有过其他语言的多进程编程经验的话,那么以上理解起来应该很容易,否则的话,你很有可能会轻视了fork调用的原理,下面的例子将帮助和加深你对它的认识。 初探: 一个简单的多进程例子 ```php <?php // 外面所有的代码都是父进程的环境 // 可以获取父进程的ID // 子进程拥有父进程的完整副本,所以此函数自然也被子进程继承了 function shutdown_function() { global $i; $pid = getmypid(); // 情况2时,这个i一直是4的,待研究…… echo PHP_EOL . "................ process shutdown i:{$i} pid: $pid " . isStartPid() . '......................' . PHP_EOL; sleep(20); } register_shutdown_function('shutdown_function'); $startPid = getmypid(); echo "start parent startPid: {$startPid}" . PHP_EOL; function isStartPid() { global $startPid; if (getmypid() == $startPid) { return ' [is startPid] '; } else { return ' '; } } // 这个for在父进程的环境内 for ($i = 1; $i <= 3; $i++) { // 由于自进程可能会继续执行for结构的原因(子进程往回执行),所以这里也可能会是子进程的部分 $_pid = getmypid(); // $i=1 时,fork()之前的部分属于父进程所有($_pid一定为开始父进程pid,此后就不一定了) echo PHP_EOL . PHP_EOL . "=====>>>>>>>>>>==== for i:{$i} pid: $_pid " . isStartPid() . '=====>>>>>>>>>======' . PHP_EOL; $pid = pcntl_fork(); // 父进程fork出来的子进程拥有父进程的副本 // 那么现在就不止父进程的环境了 // 那哪部分是父进程的代码,哪部分是子进程的代码呢,通过 $pid 判断 if ($pid < 0) { exit('fork error'); } // 接下来的代码,有两部分,子进程和父进程 // 父进程和子进程将继续执行fork之后的程序代码 // fork之后的代码属于父进程和子进程共同所有,通过判断 $pid 分隔开 if ($pid > 0) { // 父进程部分 $parentPid = getmypid(); // $pid 其实是子进程的PID(本次fork()的子进程id) // 这里也可能会出现儿子逆袭成父的进程(子进程“往回”执行时) // 情况1 $parentPid = $startPid ;情况2 不一定 echo PHP_EOL . "i:{$i} 父 parentPid: $parentPid " . isStartPid() . " (子: child_pid: $pid)" . PHP_EOL; } else if (0 == $pid) { $child_pid = getmypid(); // 子进程部分 echo PHP_EOL . " i:{$i} 子 child_pid: $child_pid " . isStartPid() . PHP_EOL; // 这行未注释时会出现子进程“往回”执行的情况,为情况2,见分析2。注释时,为情况1,见分析1 exit; } // 判断外部分属于父进程和子进程共同所有 // sleep(1); // 但是由于这是for结构,子进程执行到这里后还会继续执行,所以会继续执行for结构,这使得子进程“往回”执行了(要知道本来子进程都在fork之后的) // 当为子进程“往回”执行的情况,此时有一些微妙的细节需要注意,此结构会再次执行 pcntl_fork(),注意此时的上下文已经发生变化了 // 此子进程会再次fork一个子进程,而他本身就成为了另一个父进程(儿子逆袭当父) // 父进程更不用说了,继续执行for结构,父进程都是同一个(没发生“往回”执行的情况时),为: start parent pid echo PHP_EOL . "=====<<<<<<<<<<<==== for end i:{$i} pid: $_pid " . isStartPid() . '======<<<<<<<<<<<=====' . PHP_EOL . PHP_EOL; } // 这儿就完全是父进程的部分了 // 但这儿真的就一定是父进程才会执行的部分吗?那个在“往回”执行时逆势成父的进程呢?它算真正的父进程吗?会执行到这里吗? $pid = getmypid(); echo PHP_EOL . "=========== for after i:{$i} pid: {$pid} " . isStartPid() . PHP_EOL; ``` #### 打印分析: **分析1:** print: ```shell start parent startPid: 5955 =====>>>>>>>>>>==== for i:1 pid: 5955 [is startPid] =====>>>>>>>>>====== i:1 父 parentPid: 5955 [is startPid] (子: child_pid: 5956) =====<<<<<<<<<<<==== for end i:1 pid: 5955 [is startPid] ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:2 pid: 5955 [is startPid] =====>>>>>>>>>====== i:1 子 child_pid: 5956 ................ process shutdown i:1 pid: 5956 ...................... i:2 父 parentPid: 5955 [is startPid] (子: child_pid: 5957) =====<<<<<<<<<<<==== for end i:2 pid: 5955 [is startPid] ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:3 pid: 5955 [is startPid] =====>>>>>>>>>====== i:2 子 child_pid: 5957 ................ process shutdown i:2 pid: 5957 ...................... i:3 父 parentPid: 5955 [is startPid] (子: child_pid: 5958) =====<<<<<<<<<<<==== for end i:3 pid: 5955 [is startPid] ======<<<<<<<<<<<===== =========== for after i:4 pid: 5955 [is startPid] ................ process shutdown i:4 pid: 5955 [is startPid] ...................... i:3 子 child_pid: 5958 ................ process shutdown i:3 pid: 5958 ...................... ``` process tree: > 进程执行完毕后就自动退出了,那还怎么再用 `pstree` 命令打印进程树呢。只有让每个进程在最后时刻休眠一下,以不让其马上退出才行,要实现这个要求,shutdown_function 函数刚好合适,且只需在最初的父进程中定义一次即可,其后所有子进程都将拥有其副本。 ```shell php(5955)─┬─php(5956) ├─php(5957) └─php(5958) ``` ***** **分析2:** print: ```shell start parent startPid: 6063 =====>>>>>>>>>>==== for i:1 pid: 6063 [is startPid] =====>>>>>>>>>====== i:1 父 parentPid: 6063 [is startPid] (子: child_pid: 6064) =====<<<<<<<<<<<==== for end i:1 pid: 6063 [is startPid] ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:2 pid: 6063 [is startPid] =====>>>>>>>>>====== i:1 子 child_pid: 6064 =====<<<<<<<<<<<==== for end i:1 pid: 6063 ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:2 pid: 6064 =====>>>>>>>>>====== i:2 父 parentPid: 6063 [is startPid] (子: child_pid: 6066) =====<<<<<<<<<<<==== for end i:2 pid: 6063 [is startPid] ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:3 pid: 6063 [is startPid] =====>>>>>>>>>====== i:2 父 parentPid: 6064 (子: child_pid: 6065) =====<<<<<<<<<<<==== for end i:2 pid: 6064 ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:3 pid: 6064 =====>>>>>>>>>====== i:3 父 parentPid: 6063 [is startPid] (子: child_pid: 6067) =====<<<<<<<<<<<==== for end i:3 pid: 6063 [is startPid] ======<<<<<<<<<<<===== =========== for after i:4 pid: 6063 [is startPid] ................ process shutdown i:4 pid: 6063 [is startPid] ...................... i:3 子 child_pid: 6067 =====<<<<<<<<<<<==== for end i:3 pid: 6063 ======<<<<<<<<<<<===== =========== for after i:4 pid: 6067 ................ process shutdown i:4 pid: 6067 ...................... i:2 子 child_pid: 6066 =====<<<<<<<<<<<==== for end i:2 pid: 6063 ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:3 pid: 6066 =====>>>>>>>>>====== i:3 子 child_pid: 6069 =====<<<<<<<<<<<==== for end i:3 pid: 6066 ======<<<<<<<<<<<===== i:3 父 parentPid: 6064 (子: child_pid: 6068) =====<<<<<<<<<<<==== for end i:3 pid: 6064 ======<<<<<<<<<<<===== i:2 子 child_pid: 6065 =====<<<<<<<<<<<==== for end i:2 pid: 6064 ======<<<<<<<<<<<===== =====>>>>>>>>>>==== for i:3 pid: 6065 =====>>>>>>>>>====== i:3 子 child_pid: 6068 =====<<<<<<<<<<<==== for end i:3 pid: 6064 ======<<<<<<<<<<<===== =========== for after i:4 pid: 6068 ................ process shutdown i:4 pid: 6068 ...................... =========== for after i:4 pid: 6069 ................ process shutdown i:4 pid: 6069 ...................... i:3 父 parentPid: 6066 (子: child_pid: 6069) =====<<<<<<<<<<<==== for end i:3 pid: 6066 ======<<<<<<<<<<<===== =========== for after i:4 pid: 6066 ................ process shutdown i:4 pid: 6066 ...................... =========== for after i:4 pid: 6064 ................ process shutdown i:4 pid: 6064 ...................... i:3 父 parentPid: 6065 (子: child_pid: 6070) =====<<<<<<<<<<<==== for end i:3 pid: 6065 ======<<<<<<<<<<<===== i:3 子 child_pid: 6070 =====<<<<<<<<<<<==== for end i:3 pid: 6065 ======<<<<<<<<<<<===== =========== for after i:4 pid: 6070 =========== for after i:4 pid: 6065 ................ process shutdown i:4 pid: 6065 ...................... ................ process shutdown i:4 pid: 6070 ...................... ``` process tree: ```shell php(6063)─┬─php(6064)─┬─php(6065)───php(6070) │ └─php(6068) ├─php(6066)───php(6069) └─php(6067) ``` 通过这个打印过程和进程树分析,大家应该可以清晰地看到进程交错的执行过程、和退出的时机,以及子进程的执行细节。 如“往回执行”成为父进程再生子,注意每次“往回执行”时所携带的当前副本与每次fork的副本的关系,这些微妙的细节造成了这些效果。 原例子在这里:[PHP多进程初探 --- 开篇](https://blog.ti-node.com/blog/6363989547574886401),本文只是针对这个例子进行细节分析,以帮助大家理解。(建议大家先看看,再结合本文的分析,这样效果会比较好。) 本例虽然没有深入的演示php多进程的高级特性:进程通信、信号处理等,但是这个简单的例子却演示了php多进程的关键部分,以及最重要的细节,彻底理解和掌握这些,将为后面的学习扫清障碍。 ***** ### 僵尸进程 ***** ### 孤儿进程 ***** ### 进程通信 ***** ### 实现守护进程daemon ***** ### 实现一个通用的多进程管理模型 目标:实现一个高可用的,通用的多进程管理模型,可在多种业务模式下灵活使用。 ***** ### 参考 >[danger] 由于每段代码执行逻辑不同,所处环境也不同,所以出错的几率也不同,**一般主进程存在较小的崩溃概率,因为它逻辑直观,不会掺杂任何的业务逻辑代码,所以几乎不会出错中断(甚至设计中可以认为此部分不会出错,负载均衡部分也同理)**,但是worker进程就不同了,它是业务逻辑的具体执行部分,这里出错是不可预料的,所以对于这部分代码,可以理解为一定会出错,主进程应做好维护工作。 [PHP多进程处理并行处理任务实例](https://www.toutiao.com/a6603186787361751555/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1538717346&app=news_article_lite&utm_source=weixin&iid=33124962994&utm_medium=toutiao_android&group_id=6603186787361751555) [php多进程通信,有名管道(pcntl学习)](https://www.toutiao.com/a6483811732593574413/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1538709568&app=news_article_lite&utm_source=weixin&iid=33124962994&utm_medium=toutiao_android&group_id=6483811732593574413) [在 Linux 中安全且轻松地管理 Cron 定时任务](https://www.toutiao.com/a6608656518864699912/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1538709040&app=news_article_lite&utm_source=weixin&iid=33124962994&utm_medium=toutiao_android&group_id=6608656518864699912) [naruto | An object-oriented multi process manager for PHP :robot:](http://naruto.tigerb.cn/docs/specification-zh.html) > 在我们实际的业务场景中(PHP技术栈),我们可能需要定时或者近乎实时的执行一些业务逻辑,简单的我们可以使用unix系统自带的crontab实现定时任务,但是对于一些实时性要求比较高的业务就不适用了,所以我们就需要一个常驻内存的任务管理工具,为了保证实时性,**一方面我们让它一直执行任务(适当的睡眠,保证cpu不被100%占用),另一方面我们实现多进程保证并发的执行任务。** [PHP多进程-半城烟沙-51CTO博客](http://blog.51cto.com/vabc1314/1854640) > 实际过程中,肯定不能使用sleep()函数不让master进程退出的,需要使用pcntl_wait($status,WUNTRACED);来等待子进程的信号。(睡眠是一种低效率的阻塞,pcntl_wait才是标准的阻塞IO模型) > > ……关闭文件描述符。同文件权限掩码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法被卸载。…… [PHP多进程系列笔记(五) - 飞鸿影下 - SegmentFault 思否](https://segmentfault.com/a/1190000015390057?utm_source=tag-newest) [守护进程之PHP实现 - 假装是个程序员 - SegmentFault 思否](https://segmentfault.com/a/1190000008916867) [php:多进程执行任务 - php:从入门到颈椎康复 - SegmentFault 思否](https://segmentfault.com/a/1190000015482154?utm_source=tag-newest) [进程控制(2): 进程操作 - XiaoManon - 博客园](https://www.cnblogs.com/xiaomanon/p/4201006.html) > 由于创建的新进程和父进程在系统看来是地位平等的两个进程,所以运行机会也是一样的,我们不能够对其执行先后顺序进行假设,先执行哪一个进程取决于系统的调度算法。如果想要指定运行的顺序,则需要执行额外的操作。正因为如此,程序在运行时并不能保证输出顺序和上面所描述的一致。 [基于swoole扩展实现真正的PHP数据库连接池 - 圆旭 - 博客园](https://www.cnblogs.com/pinganzi/p/6640507.html) > PHP的数据库连接池一直以来都是一个难题,很多从PHP语言转向Java的项目,大多数原因都是因为Java有更好的连接池实现。**PHP的MySQL扩展提供了长连接的API,但在PHP机器数量较多,规模较大的情况下,mysql_pconnect非但不能节约MySQL资源,反而会加剧数据库的负荷。** [PHP连接池实现的一种想法 - frf12的博客 - CSDN博客](https://blog.csdn.net/frf12/article/details/54666762) > 在想JAVA可以实现连接池,那么PHP呢?我们用PHP做WEB开发,他们是不常驻内存的,连接池要放在哪,又以何种方式去获取链接呢。 > 利用php的多进程模型去实现一个数据库连接池。 > 我的想法是用先在服务器上开启一个PHP守护进程,这个守护进程打开并维护多个链接对象,起着连接池的作用,然后每一次数据库的访问都由这个守护进程发起,这是进程间通讯,具体使用管道还是网络都可以,只要把SQL语句传给守护进程,守护进程启动一个闲置的连接去执行这条SQL,并将放回结果以进程间通信的方式返回。 (注意:不是把连接池对象直接传递给业务进程使用(也没法传递,进程通信,对象传递?),而是 守护进程充当代理的角色,所有sql业务交给它执行,类似rpc调用了,但这样性能能够提升吗,能提升多少呢) [关于php的一篇文章《php 应该使用缓存和连接池》_数据库_Tangxy723的专栏-CSDN博客](https://blog.csdn.net/tangxy723/article/details/8607167) ***** [swoole的进程模型](https://blog.ti-node.com/blog/6379580337835474944) > 很多phper一直停留在php web开发的mvc CURD中,也听到很多人对自己陷入这种困境中多有不满,但又不知道如何提高自己,摆脱困境。活脱脱就像一直趴在玻璃上的苍蝇,前途一片光明,就是飞不出去,可悲可叹。 话说回来,实际上做到一名合格的CURDer也并不是一件容易的事情,万万不可眼高手低。 [swoole的协程是个什么鬼](https://blog.ti-node.com/blog/6411537544197963777) > 实际上你可以这么理解,就是master进程可以hold住上万个TCP连接是没有任何问题的,因为master进程内部异步非阻塞的,但是仅仅hold住上万个TCP连接本身是没有任何意义的,因为有数据传输的TCP连接才是有意义的。一旦有数据传输就意味着有业务逻辑产生了,那么master进程并不负责具体业务逻辑代码了,处理这个业务逻辑的活儿交给worker进程来干,然后干完后再由master进程返回给客户端。 [老旧话题:yield是个什么玩意(上)](https://blog.ti-node.com/blog/6426271125306605568) > 这是个bug,这是个php的bug,至少我正在使用的PHP 7.1.17版本是有这个bug的,你不要以为这里面有什么高深莫测的技术,就是bug而已。(php却是有一些这样的已知和未知BUG,这是无可避免的,毕竟php本身也是一个软件) [PHP多进程初探 --- 开篇](https://blog.ti-node.com/blog/6363989547574886401) > 由于多进程在apache或者fpm环境下无法正常运行,所以大家一定要在php cli环境下执行下面php代码。 > > fpm与多进程的PHP结合情况变复杂了,所以保险起见还是只在cli下使用PHP的多进程 > > 每个动态请求都是由 php-fpm 进程fork出来一个子进程来处理(执行我们的代码部分),此时子进程再fork进程,做多进程管理,就不太好了,毕竟这不是php-fpm的主职,并且由于多进程的复杂性,资源难以管理,如果用不好还可能使进程崩溃,显然这些给 php-fpm 进程加重了负担,会影响系统的并发能力,所以只能在CLI下使用多进程。(这就像是让厨师去做迎宾,结果是只会鸡飞蛋打,赔了夫人又折兵) > > 这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并不是真正的完全副本。更多是采用了COW(Copy On Write)即**写时复制**的技术来节约存储空间。简单来说,如果父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操作,这就叫做写时复制。 [PHP多进程初探 --- 孤儿和僵尸](https://blog.ti-node.com/blog/6375380006637404161) > 1. 父进程不能先退出,否则子进程就成孤儿进程了。 > 2. 父进程除了不能先退出外,还要善后,即调用`wait`或者`waitpid`等函数对子进程的相关资源(使用过的变量、打开的文件描述符等等)进行清理。 > > 所以问题就在于,父进程如何保持不退出以等待子进程了? > 有两种方案:1. 父进程中使用wait阻塞等待子进程退出;2. 父进程中安装信号处理监听器,监听子进程的退出信号。 [PHP多进程初探 --- 信号](https://blog.ti-node.com/blog/6375675957193211905) > 子进程在退出的时候,会向父进程发送一个信号,叫做SIGCHLD,那么父进程一旦收到了这个信号,就可以作出相应的回收动作,也就是执行pcntl_waitpid(),从而解决掉僵尸进程 [php进程daemon化的正确做法](https://blog.ti-node.com/blog/6343348095782223873) > 其次是代码中如果有echo或者print_r之类的输出文本 , 会被输出到当前的终端窗口中(进程绑定的输出终端) [PHP多进程初探 --- 再次谈daemon进程](https://blog.ti-node.com/blog/6379889763461103616) > 一些重要的概念:1. 进程组;2. 会话;3. 控制终端 [PHP多进程初探 --- 利用多进程开发点儿东西吧](https://blog.ti-node.com/blog/6379968168328167424) [PHP多进程初探 --- 进程间通信二三事](https://blog.ti-node.com/blog/6379989346195341312) > 往往开启多进程的目的是为了一起干活加速效率,前面说了不同进程之间的内存空间都是相互隔离的,也就说进程A是无法读或写进程B中的任何数据内容的,反之亦然。但是,有些时候,多个进程之间必须要有相互通知的机制,用职场上的话来说就叫“及时沟通”。大家都在一起做同一件事情的不同部分,彼此之间“及时沟通”是很重要的。 > 确切说,如果不用sem的话,上述的运行结果在一定概率下就会产生1而不是2。但是只要加入sem,那就一定保证100%是2,绝对不会出现其他数值。 [kill命令_Linux kill 命令用法详解:删除执行中的程序或工作](http://man.linuxde.net/kill) [极客漫画:不要使用 SIGKILL 的原因(看哭了)](https://www.toutiao.com/a6454826726273843726/?tt_from=weixin&app=news_article&iid=12619555732&wxshare_count=1) [The Smallest Bash Script in the Universe](https://blog.twentytwotabs.com/the-smallest-bash-program-in-the-universe/) shell 脚本是如何执行的,以及为何以 `#!` 开头 [进程与线程的一个简单解释](https://mp.weixin.qq.com/s/COg7NwSJzrLqw7qIWtOK8A) [神奇的ThreadLocal](https://mp.weixin.qq.com/s/5aRRcsua9CF3oeqRbXDb9g) [高性能线程间消息传递库Disruptor概述](https://mp.weixin.qq.com/s/fmqF4qeE7Nr7c1hVAuKROA) [通过 Node.js 的 Cluster 模块源码,深入 PM2 原理](https://mp.weixin.qq.com/s/668R5YheK0GGd8kUGtRFVA) [深入理解Node.js 进程与线程(8000长文彻底搞懂)](https://mp.weixin.qq.com/s/N6Omr5HwSPl6JjE2ultoVg) [深入理解计算机系统:进程](https://mp.weixin.qq.com/s/z6K8C56FnNVKu6XAQefViQ) [骚操作 | 不重启 JVM,替换掉已经加载的类,偷天换日?](https://mp.weixin.qq.com/s/zJaTr5SL-fPLXd9UprTQ0Q) ~~~ 计算机应该是人类有史以来最伟大的发明之一,从电磁感应磁生电,到高低电压模拟0和1的比特,再到二进制表示出几种基本类型,再到基本类型表示出无穷的对象,最后无穷的对象组合交互模拟现实生活乃至整个宇宙。 两千五百年前,《道德经》有言:“道生一,一生二,二生三,三生万物。” 两千五百年后,计算机的发展过程也大抵如此吧。 ~~~ [用了这么久的数据库连接池,你知道原理吗?](https://mp.weixin.qq.com/s/UPerKMFtUaCR3ozva9UHug) [小白科普:虚拟化简史](https://mp.weixin.qq.com/s/KVOBKVmkm-Ogvcne3_Xxog) [Java线程为何没有Running状态?我猜你不知道。](https://mp.weixin.qq.com/s/w7ZkGq4rAHe4OlOSxyuoWw) > 某种意义上,这也是控制反转(IoC)机制的一种体现,cpu不用反复去询问硬盘,这也是所谓的“好莱坞原则”—Don’t call us, we will call you.好莱坞的经纪人经常对演员们说:“别打电话给我,(有戏时)我们会打电话给你。” [计算机内存管理介绍](https://mp.weixin.qq.com/s/n_adWFPgW5LJiEepADueOQ) [SpringCloud微服务如何优雅停机及源码分析](https://mp.weixin.qq.com/s/3xTwdXCeR_7zepBOI8vZBw) [Java 中几种常用的 RPC 框架介绍](https://mp.weixin.qq.com/s/hPIQwXR4ZtxgTMwieDSD6A) [揭开 asyncio 的神秘面纱 :从 hello world 说起](https://mp.weixin.qq.com/s/ltORoBfRowAR8iXYD3NDQw) > asyncio 是用来编写并发程序的库。在爬虫、客户端应用等开发场景中, 我们经常会需要将多个网络请求并行化来提高程序性能,而 asyncio 框架正好可以很方便的帮助我们实现这个需求。 [LINUX PID 1 和 SYSTEMD - coolshell](https://coolshell.cn/articles/17998.html) [前端进击的巨人(1):执行上下文与执行栈,变量对象](https://mp.weixin.qq.com/s/lAvyjfBZvX0E50QiW3aW7w) [KA,连接池居然这么简单?](https://mp.weixin.qq.com/s/y8GEAY0R5YXEZZ3erCZJ4A) [揭开进程、线程、绿色线程的神秘面纱](https://mp.weixin.qq.com/s/uTd86WsHQZJSnll5Plt_4w) [Redis是单线程的,但Redis为什么这么快?](https://mp.weixin.qq.com/s/v70ElApJbgoD8_0A494VIg) [编程中的栈指的是什么?](https://mp.weixin.qq.com/s/7zAJwCrwUcrROFWmypDvbQ) > IIFE模式:匿名函数自调用(闭包 > stack的第一种含义是一组数据的存放方式,特点为LIFO,即后进先出(Last in, first out)。 [什么是线程安全,你真的了解吗?](https://mp.weixin.qq.com/s/Er5LfxFiCUrbByPjdJ4DNg) [一文看懂线程的生命周期,利用线程池模拟群发短信](https://mp.weixin.qq.com/s/gCnvvpavRPmhDMD6d65KIg) > 线程池,让线程阻塞,循环没事的 > 传统不阻塞的话,执行完毕后就结束生命周期了,所以要不想结束,就只有阻塞挂起了。 > 压榨,忙碌起来 [编程这么久你可能没真正了解进程](https://mp.weixin.qq.com/s/FRwg2WPbYkdnN71dCGPe6w) [一个想休息的线程:JVM到底是怎么处理锁的?怎么不让我阻塞呢?](https://mp.weixin.qq.com/s/sIMowR_qjskg-WeriMiIlg) [伪共享和缓存行填充,Java并发编程还能这么优化!](https://mp.weixin.qq.com/s/S_x39EB3nPx6oCB9Jy0EZA) [为什么Goroutine能有上百万个,Java线程却只能有上千个?](https://m.toutiaocdn.com/group/6577255545676235272/?iid=33124962994&app=news_article_lite&timestamp=1532459481&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share) [ThreadLocal父子线程数据传递方案](https://mp.weixin.qq.com/s/D9ZOGqmW17l8p8U5cvn0Rw) > 不能依赖于外部 [一个故事讲完进程、线程和协程](https://mp.weixin.qq.com/s/zuWRx1FGuBC-_HwuA7jK3w) [ThreadLocal父子线程数据传递方案(修正篇)](https://mp.weixin.qq.com/s/wkryihr9tuCuyqakikC4GQ) [内存那些事](http://toutiao.com/group/6552369670400246280/?iid=31395168747&app=news_article_lite&timestamp=1525642790&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share) [一个故事讲完进程、线程和协程](https://mp.weixin.qq.com/s/zuWRx1FGuBC-_HwuA7jK3w) [【底层原理】用户进程缓冲区和内核缓冲区](https://mp.weixin.qq.com/s/W8GGupa6FuizbWU9CJ5B_Q) > 计时器:计算机能计时是因为晶体振荡器产生的电磁脉冲。那么所有的定时任务都是以它为基础的。 [线程安全与线程不安全的区别](http://toutiao.com/group/6553138195117113870/?iid=31395168747&app=news_article_lite&timestamp=1525794589&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share) > 可见性和有序性 > 多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程 [谈谈Java中常见的线程安全模型](https://mp.weixin.qq.com/s/_DixMb-gay67XGy_8vb8Kg) [【底层原理】用户进程缓冲区和内核缓冲区](https://mp.weixin.qq.com/s/W8GGupa6FuizbWU9CJ5B_Q) [进程与线程的一个简单解释](https://mp.weixin.qq.com/s/COg7NwSJzrLqw7qIWtOK8A) [那些烦人的同步和互斥问题](https://mp.weixin.qq.com/s/KSCaMjuGX_9FxAq2kFLprg) [C老头和Java小子的硬盘夜话](https://mp.weixin.qq.com/s/ugw8s8YsYjuxjdfMJBKjZw) [【C++札记】C++11并发编程(一)开启线程之旅](https://mp.weixin.qq.com/s/DypfPCogpsvcYRodXqjalQ) [关于PHP协程与阻塞的思考](https://mp.weixin.qq.com/s/WxcP_ghWyY3kWoPi_8dC8w) [Node.js : 我只需要一个店小二](https://mp.weixin.qq.com/s/BzrAacmJZEFRXE3vijCVQQ) [我是一个线程(修订版)](https://mp.weixin.qq.com/s/-BMCUuIWYE3O_oC3ZNNJRg) [Go 为什么这么“快”](https://mp.weixin.qq.com/s/ihJFa5Wir4ohhZUXVSBvMQ) [Asynchronous programming. Blocking I/O and non-blocking I/O](https://luminousmen.com/post/asynchronous-programming-blocking-and-non-blocking) > 一组系列文章,从操作系统的高度,较为通俗地介绍如何认识异步编程。 > 异步的本质,底层实现原理 [你能搞懂connectTimeout和socketTimeout的区别么?](https://mp.weixin.qq.com/s/WYIoGvELo4pFUtkHtQpzGg) [资深程序员总结:分析Linux进程的6个方法,我全都告诉你](https://mp.weixin.qq.com/s/ybDvZcg8oeoQ-6wKXYY8ng) [面试官:兄弟,谈谈你对分布式系统原理的理解](https://mp.weixin.qq.com/s/vY_NV1_tcTOvVs8RPMb_vg) [ZooKeeper 源码和实践揭秘](https://mp.weixin.qq.com/s/DigeE4YxuT55cSeyb1q1tQ) [漫画:什么是Linux管道](https://mp.weixin.qq.com/s/aXRk85tezwi8xUr_xBy3xg) [我是一个函数](https://mp.weixin.qq.com/s/khV64qj0LhitngVrRBiLug) [操作系统是个大骗子?](https://mp.weixin.qq.com/s/F_rGON3DCwyrWi4V9Vj6uQ) [图解 | 线程的麻烦事儿,Actor能解决吗?](https://mp.weixin.qq.com/s/31Pj6-wrMx8kjYoSy_b7FA) > 说说我的看法,其实关于并发竞争,总体就两类方案: 一种是保守派,一种是侥幸派。 保守派的做法是把所有操作串行化,采用的方法如悲观锁、操作队列等。 侥幸派的做法是碰碰运气,成功了说明运气好,不成功继续碰碰运气,采用的方法如乐观锁、版本号、CAS等,其实原理都一样。 其次是关于事务,无论是本地的还是分布式的,都无法100%得到保证。事务的关键点是在失败时会自动回滚,但是回滚可靠吗? 严格来说任务事情都无法100%可靠,我们要做的是尽量让其可靠以及准备一些补偿方案,记录一些关键数据信息,实在不行,最后人肉恢复或调整。 [程序员精进之路:性能调优利器--火焰图](https://mp.weixin.qq.com/s/GFPMIJGT4x6Q_86ZZfOOpg) [就为了一个原子操作,其他CPU核心罢工了](https://mp.weixin.qq.com/s/jx0EajGXGrM3fR14P9Bm7Q) [内核地址空间大冒险4:线程切换](https://mp.weixin.qq.com/s/dpzB7k1kdkClohRWA-ludQ) [两个程序悲催的进化旅程](https://mp.weixin.qq.com/s/9EUsVWhEr8sMrqZES2ziww) [数据库链接池终于搞对了,直接从100ms到3ms](https://mp.weixin.qq.com/s/ZdDpgXnjStRoZIlh-3iRsg) [困难人生之CLang的wait以及waitpid](https://t.ti-node.com/thread/6472490733105315841) [你不知道的 WeakMap](https://mp.weixin.qq.com/s/iacn5m0qjaAPS2huG2pKRA) [什么时候不要使用微服务?以Istio为例](https://mp.weixin.qq.com/s/doJcgfcymTaPNDEUA-tXVQ) [万级K8s集群背后etcd稳定性及性能优化实践](https://mp.weixin.qq.com/s/SZgSbWwKNZTVJOZ_pKLblA) [浅谈RPC那些事儿\[1\]](https://mp.weixin.qq.com/s/EZV_fdFB8feTuDe-riqN6A) [超详细!微服务RPC框架内核解析!](https://appzcodh6sz4402.h5.xiaoeknow.com/v1/course/alive/l_5f22d519e4b0dc56a6d0c802?access_entry=1&app_id=appZCodH6sz4402&entry=2&entry_type=2001&func_type=1&scene=%E5%88%86%E4%BA%AB&share_type=100&share_user_id=u_5ef724179afd1_MxRvMamspI&type=2&available=true&is_redirect=1) > 保存上下文,上下文是什么,其实就是当前的进程,只要frck一下,让这个进程保持就可以了。 > 异步处理可以提高服务的吞吐能力,因为服务能快速响应,不需要等待执行结果,而工人进程会不断消费任务,哪怕在没有请求时可能也还在工作,所以cpu的利用几乎是饱和效率的,而同步处理经常完成瞬时压力大,大量io集中在一时间段,导致整体响应都很慢,过后cpu反而被闲置了。 [操作系统和并发的爱恨纠葛](https://mp.weixin.qq.com/s/v0xLt69qOEkIiLJlSaHxEw) [Shell:管道与重定向](https://mp.weixin.qq.com/s/zqt8j4Ag0cTYJgb5E30x1A) ***** last update:2018-10-18 17:07:15