## 进程
![](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×tamp=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×tamp=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×tamp=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×tamp=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×tamp=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×tamp=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
- 开始
- 公益
- 更好的使用看云
- 推荐书单
- 优秀资源整理
- 技术文章写作规范
- SublimeText - 编码利器
- PSR-0/PSR-4命名标准
- php的多进程实验分析
- 高级PHP
- 进程
- 信号
- 事件
- IO模型
- 同步、异步
- socket
- Swoole
- PHP扩展
- Composer
- easyswoole
- php多线程
- 守护程序
- 文件锁
- s-socket
- aphp
- 队列&并发
- 队列
- 讲个故事
- 如何最大效率的问题
- 访问式的web服务(一)
- 访问式的web服务(二)
- 请求
- 浏览器访问阻塞问题
- Swoole
- 你必须理解的计算机核心概念 - 码农翻身
- CPU阿甘 - 码农翻身
- 异步通知,那我要怎么通知你啊?
- 实时操作系统
- 深入实时 Linux
- Redis 实现队列
- redis与队列
- 定时-时钟-阻塞
- 计算机的生命
- 多进程/多线程
- 进程通信
- 拜占庭将军问题深入探讨
- JAVA CAS原理深度分析
- 队列的思考
- 走进并发的世界
- 锁
- 事务笔记
- 并发问题带来的后果
- 为什么说乐观锁是安全的
- 内存锁与内存事务 - 刘小兵2014
- 加锁还是不加锁,这是一个问题 - 码农翻身
- 编程世界的那把锁 - 码农翻身
- 如何保证万无一失
- 传统事务与柔性事务
- 大白话搞懂什么是同步/异步/阻塞/非阻塞
- redis实现锁
- 浅谈mysql事务
- PHP异常
- php错误
- 文件加载
- 路由与伪静态
- URL模式之分析
- 字符串处理
- 正则表达式
- 数组合并与+
- 文件上传
- 常用验证与过滤
- 记录
- 趣图
- foreach需要注意的问题
- Discuz!笔记
- 程序设计思维
- 抽象与具体
- 配置
- 关于如何学习的思考
- 编程思维
- 谈编程
- 如何安全的修改对象
- 临时
- 临时笔记
- 透过问题看本质
- 程序后门
- 边界检查
- session
- 安全
- 王垠
- 第三方数据接口
- 验证码问题
- 还是少不了虚拟机
- 程序员如何谈恋爱
- 程序员为什么要一直改BUG,为什么不能一次性把代码写好?
- 碎碎念
- 算法
- 实用代码
- 相对私密与绝对私密
- 学习目标
- 随记
- 编程小知识
- foo
- 落盘
- URL编码的思考
- 字符编码
- Elasticsearch
- TCP-IP协议
- 碎碎念2
- Grafana
- EFK、ELK
- RPC
- 依赖注入
- 开发笔记
- 经纬度格式转换
- php时区问题
- 解决本地开发时调用远程AIP跨域问题
- 后期静态绑定
- 谈tp的跳转提示页面
- 无限分类问题
- 生成微缩图
- MVC名词
- MVC架构
- 也许模块不是唯一的答案
- 哈希算法
- 开发后台
- 软件设计架构
- mysql表字段设计
- 上传表如何设计
- 二开心得
- awesomes-tables
- 安全的代码部署
- 微信开发笔记
- 账户授权相关
- 小程序获取是否关注其公众号
- 支付相关
- 提交订单
- 微信支付笔记
- 支付接口笔记
- 支付中心开发
- 下单与支付
- 支付流程设计
- 订单与支付设计
- 敏感操作验证
- 排序设计
- 代码的运行环境
- 搜索关键字的显示处理
- 接口异步更新ip信息
- 图片处理
- 项目搭建
- 阅读文档的新方式
- mysql_insert_id并发问题思考
- 行锁注意事项
- 细节注意
- 如何处理用户的输入
- 不可见的字符
- 抽奖
- 时间处理
- 应用开发实战
- python 学习记录
- Scrapy 教程
- Playwright 教程
- stealth.min.js
- Selenium 教程
- requests 教程
- pyautogui 教程
- Flask 教程
- PyInstaller 教程
- 蜘蛛
- python 文档相似度验证
- thinkphp5.0数据库与模型的研究
- workerman进程管理
- workerman网络分析
- java学习记录
- docker
- 笔记
- kubernetes
- Kubernetes
- PaddlePaddle
- composer
- oneinstack
- 人工智能 AI
- 京东
- pc_detailpage_wareBusiness
- doc
- 电商网站设计
- iwebshop
- 商品规格分析
- 商品属性分析
- tpshop
- 商品规格分析
- 商品属性分析
- 电商表设计
- 设计记录
- 优惠券
- 生成唯一订单号
- 购物车技术
- 分类与类型
- 微信登录与绑定
- 京东到家库存系统架构设计
- crmeb
- 命名规范
- Nginx https配置
- 关于人工智能
- 从人的思考方式到二叉树
- 架构
- 今日有感
- 文章保存
- 安全背后: 浏览器是如何校验证书的
- 避不开的分布式事务
- devops自动化运维、部署、测试的最后一公里 —— ApiFox 云时代的接口管理工具
- 找到自己今生要做的事
- 自动化生活
- 开源与浆果
- Apifox: API 接口自动化测试指南