## 進程

### 進程是什么?
如果你搜索“什么是進程?”,你大概都會看到這樣的答案:“進程是程序的基本執行實體”,“進程是系統進行資源分配和調度的基本單位”,...等等。
看了后你還是不懂什么是進程,因為這個回答太官方了,除了讓你不明覺厲之外沒有作用。
那為什么進程的概念很難說清楚呢,或者說為什么向人描述清楚“進程是什么?”的這個問題不容易呢。
這要從我們寫的代碼是怎么在計算機中被執行的說起了,并不是像我們想象中的那樣,自上而下,獨占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 接口自動化測試指南