## 多進程/多線程
### 前言

<p class="img-desc">這圖夠形象吧</p>
// 
程序分為兩種,`單進程/單線程` 和 `多進程/多線程` 兩種。
(為了方便,下文以“單”代指 `單進程/單線程` ,“多”代指 `多進程/多線程` )。
“單”程序不用考慮并發問題(比如瀏覽器中的javascript),復雜度會比“多”程序低很多。
多進程/多線程 程序在很多時候可以提高程序的效率,尤其是網絡時代的到來。“多”程序的開發需要轉變以往開發“單”程序時的開發思路和方式,以及對程序運行的理解,多進程對共享資源的使用,并發問題等等,這些給程序的開發維護帶來了更大的挑戰,對程序員的要求更高。
* * * * *
### 參考資料
[【開源組件】深入淺出Nginx](http://mp.weixin.qq.com/s/31DGDYpDHcYg-4qM4OczxA)
[nginx、swoole高并發原理初探 - 暢想代碼 - SegmentFault](https://segmentfault.com/a/1190000007614502?utm_source=coffeephp.com)
<pre>
1、同步與異步
①同步與異步的理解
同步與異步的重點在消息通知的方式上,也就是調用結果通知的方式。
同步
當一個同步調用發出去后,調用者要一直等待調用結果的通知后,才能進行后續的執行
異步:
當一個異步調用發出去后,調用者不能立即得到調用結果的返回。
異步調用,要想獲得結果,一般有兩種方式:
1、主動輪詢異步調用的結果;
2、被調用方通過callback來通知調用方調用結果。
②:生活實例
同步買奶茶:小明點單交錢,然后等著拿奶茶;
異步買奶茶:小明點單交錢,店員給小明一個小票,等小明奶茶做好了,再來取。
異步買奶茶,小明要想知道奶茶是否做好了,有兩種方式:
1、小明主動去問店員,一會就去問一下:“奶茶做好了嗎?”...直到奶茶做好。
2、等奶茶做好了,店員喊一聲:“小明,奶茶好了!”,然后小明去取奶茶。
**關于2問題:小明得一直都在,雖然他不用一遍遍去問好了沒有,但是他得等著店員什么時候來叫他,并且也不能預料到什么時候回來叫他,所以他不得不一直等著不能離開奶茶店,只不過他等著的時候可以干點別的小事而已。**
</pre>
**異步是一種編程模型,MQ是一種異步實現方式。**
(補充:隊列實際上也是一種異步模型的應用)
你可以走離開店鋪,但是你得告訴服務員一個憑證,以便奶茶做好后可以聯系到你。
[linux - 單線程多路復用和多線程加鎖的區別 - SegmentFault](https://segmentfault.com/q/1010000004026316)
[大家做linux C/C++網絡編程時,啥時用到多線程或者多進程啊? - SegmentFault](https://segmentfault.com/q/1010000007784175)
> 多個進程或者線程無非就是要多占用點CPU的時間片,讓程序運行效率更高點。不過進程間通信,線程上下文切換,同步等問題同樣會對性能有些影響。服務器程序為了提高CPU的利用率,采用多進程或多線程的模型是比較常見的做法,而客戶端程序一般來說的確單進程單線程就可以了。另外 @Hacken 的回答我不贊同,并不是說單進程和單線程的模型就無法同時服務多個客戶端了,這里面主要要依賴IO復用技術。反過來講,同時服務1000個客戶端,難道要同時開1000個線程?顯然不可能。
> 生活中常說的,你們兩個人的工作要同步啊,什么跟什么事同步進行啊之類的,這個同步的意思指的是,強調某些事物或工作的頻率要保持一致。這個同步和編程中的同步不同哦,就像雷鋒和雷峰塔的關系。
[網絡編程 - I/O復用到底是什么意思 - SegmentFault](https://segmentfault.com/q/1010000004543463)
[I/O多路復用和Socket - 全干工程師 - SegmentFault](https://segmentfault.com/a/1190000004537204)
[select、poll、epoll之間的區別總結\[整理\] - Anker's Blog - 博客園](http://www.cnblogs.com/Anker/p/3265058.html)
[IO多路復用之epoll總結 - Anker's Blog - 博客園](http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html)
[異步通知,那我要怎么通知你啊? · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/356621)
[定時-時鐘-阻塞 · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/400090)
[多進程/多線程 · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/419460)
[javascript - 究竟能不能用死循環?或者其實我們就活在一個死循環的世界中? - SegmentFault](https://segmentfault.com/q/1010000009586182)
[mysql - PHP定時通知、按時發布怎么做? - SegmentFault](https://segmentfault.com/q/1010000009508176)
[工作線程數究竟要設置為多少 | 架構師之路](http://mp.weixin.qq.com/s/BRpngTEFHjzpGv8tkdqmPQ)
[為什么操作系統的單線程比多線程好的多?-悟空問答](https://www.wukong.com/question/6477192237145915661/)
[架構師之路,季度精選40篇](http://mp.weixin.qq.com/s/vLebPT-58Jw-Q7afhkgHSg)
[進程和線程到底誰才是雞肋?他們的區別在哪里?神級程序員解惑!](http://www.toutiao.com/a6481910423351198222/?tt_from=weixin&utm_campaign=client_share&app=news_article&utm_source=weixin&iid=12619555732&utm_medium=toutiao_android&wxshare_count=1)
[為什么串口比并口快?-OSDIY的回答-悟空問答](https://www.wukong.com/answer/6499404386807054605/?iid=12619555732&app=news_article&share_ansid=6499653269822898446&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share)
[電腦cpu的核心與線程是什么意思?-蒙面侍衛的回答-悟空問答](https://www.wukong.com/answer/6502689903652897037/?iid=12619555732&app=news_article&share_ansid=6501551892177355021&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share)
[一篇文章看懂Java并發和線程安全](https://www.toutiao.com/a6513707798830776846/?tt_from=weixin&utm_campaign=client_share×tamp=1516737598&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1)
> 談到多線程,我們很容易與高性能畫上等號,但是并非如此,舉個簡單的例子,從1加到100,用四個線程計算不一定比一個線程來得快。因為線程的創建和上下文切換,是一筆巨大的開銷。
[線程安全與線程不安全的區別](https://www.toutiao.com/i6553138195117113870/?tt_from=weixin&utm_campaign=client_share&from=singlemessage×tamp=1525794589&app=news_article_lite&utm_source=weixin&iid=31395168747&utm_medium=toutiao_android&wxshare_count=2&pbid=6549783428988438030)
> 多個線程執行時,CPU對線程的調度是隨機的,我們不知道當前程序被執行到哪步就切換到了下一個線程
[阻塞非阻塞與同步異步有什么區別?-IT老友的回答-悟空問答](https://www.wukong.com/answer/6492953923190522125/?showComment=6492953923190522125&commentId=1585273588409358)
> 你最后一段說錯了。阻塞是指,調用方必須等到下游被調用方執行完畢返回結果才能繼續執行,在被調用方未執行完畢返回結果前,上游調用方處于阻塞掛起狀態。這就是阻塞。非阻塞是下游被調用方的執行不會阻塞上游調用方,等到執行完畢,將結果通知到上游調用方,在此期間,上游調用方不會被阻塞,可以繼續做別的事,如每隔一段時間的詢問被調用方是否完成,<del>然后等著通知就可以了</del>(收到通知不是非阻塞,是信號驅動式IO模型)。
[程序中的代碼段、數據段、堆、棧是怎么回事](https://www.toutiao.com/a6512907902972330509/?tt_from=weixin&utm_campaign=client_share×tamp=1516475144&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1)
[當你在 Linux 上啟動一個進程時會發生什么?](http://mp.weixin.qq.com/s/kSza_aaBt689tRMUH8iMSQ)
[php非阻塞訪問url 解析socket阻塞與非阻塞,同步與異步 - 橙虛緣空間 - CSDN博客](http://blog.csdn.net/qq43599939/article/details/50570098)
[電腦CPU有超線程,為什么手機CPU沒有超線程設計?-數碼偵探的回答-悟空問答](https://www.wukong.com/answer/6514182743021060356/?iid=25315997380&app=news_article&share_ansid=6514182743021060356&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share)
> 超線程技術是指,對于單一處理器核心來說來說,**雖然也可以每秒鐘處理成千上萬條指令,但是在某一時刻,只能夠對一條指令進行處理**,也就是單線程。超線程技術能夠把一個物理處理器在軟件層變成兩個邏輯處理器,可以使處理器在某一時刻,同步并行處理更多指令和數據,也就是超出數量(2)的線程數。
[【系統編程】你所不知道的TIME_WAIT和CLOSE_WAIT(上)](http://mp.weixin.qq.com/s/y-7X7juYhcgnPN4AchtrmA)
[【系統編程】你所不知道的TIME_WAIT(下)](http://mp.weixin.qq.com/s/MlyIDf9eWRn5x6V9eOaqWg)
[【系統編程】并發服務器(一):簡介](https://mp.weixin.qq.com/s/de3YqaSFaxUyiBMEW7fsKg)
[【系統編程】并發服務器(二):線程](https://mp.weixin.qq.com/s/KkrSxVZhOI22JDk4K20cxg)
[深入理解 Java 多線程核心技術](https://mp.weixin.qq.com/s/rHnzqlzJusIVNO7X7mBDkA)
[小白科普:線程和線程池](https://mp.weixin.qq.com/s/qzoLgNNSZD2NrzBEINVuUg)
[一個故事講完進程、線程和協程](https://mp.weixin.qq.com/s/zuWRx1FGuBC-_HwuA7jK3w)
~~~
文中:就這么依次循環下去。
總結:不結束執行,就需要無限循環(可控),也就是監聽,服務,即循環。
[一分鐘了解nohup和&的功效](https://mp.weixin.qq.com/s/nyT-FPdIUdJUiUCYVGEnTg)
問:環程序,在實際軟件中,有沒有應用呢?以前學校老師c語言的課上總說,千萬不要寫出死循環的代碼,死循環就是最嚴重的BUG。不知道是不是這樣的,但是感覺現在很多軟件,比如隊列,監聽接口等,底層實現好像都是死循環,別人說這叫,空循環,無限循環之類的,并不認為死循環是BUG。同時我還想知道,這樣死循環的代碼,CPU是怎么對待的,會持續搶占cpu時間片嗎,如果這樣,那別的進程怎么辦?希望大神解答一下,或者給個提示讓我去找找資料。謝謝了!
回復:服務(service)的本質就是死循環程序,監聽端口,接收并響應請求
服務的本質就是死循環,哈哈,那么就剩第二個問題了,cpu如何對待死循環的程序?
~~~
~~~
問:一個web端過來的請求是不是就意味著占用著一個進程 如果是cpu密集型操作就會一直占用該進程直至請求結束 并發情況下其它請求需要等待空閑進程?
回復:即使是CPU密集型, 也會在時間片到期的時候,讓出CPU的。然后OS再調度,看看誰來執行。
~~~
[線程與進程的前世今生](https://mp.weixin.qq.com/s/oHodaBJEmCzh8g4Ihslesw)
[PHP Socket 通訊 TCP | Laravel China 社區 - 高品質的 Laravel 開發者社區](https://laravel-china.org/articles/9433/php-socket-communication-tcp)
> Socket,是封裝好的通信協議的接口,提供網絡通訊的能力,更加方便使用協議棧。Socket的操作是 I/O 的集合。(計算機解決問題往往是通過一層一層的封裝)
[【追光者系列】HikariCP 連接池配多大合適(第一彈)?](https://mp.weixin.qq.com/s/EVNIIyTQ3i1AgZKc4JRgWw)
> 眾所周知,一個CPU核心的計算機可以同時執行數十或數百個線程,其實這只是操作系統的一個把戲-time-slicing(時間切片)。實際上,該單核只能一次執行一個線程,然后操作系統切換上下文,并且該內核為另一個線程執行代碼,依此類推。這是一個基本的計算法則,給定一個CPU資源,按順序執行A和B 總是比通過時間片“同時” 執行A和B要快。一旦線程數量超過了CPU核心的數量,添加更多的線程就會變慢,而不是更快。
某用戶做過測試(見參考資料),得到結論 **1個線程寫10個記錄比10個線程各寫1個記錄快。** 使用jvisualvm監控程序運行時,也可以看出來thread等待切換非常多。設計多線程是為了盡可能利用CPU空閑等待時間(等IO,等交互…),它的代價就是要增加部分CPU時間來實現線程切換。假如CPU空閑等待時間已經比線程切換更短,(線程越多,切換消耗越大)那么線程切換會非常影響性能,成為系統瓶頸。
[七大進程間通信和線程同步](https://mp.weixin.qq.com/s/VV_mTpuOYFIZRb94mwhr2Q)
[六大高并發模型](https://mp.weixin.qq.com/s/PgWUkY5cm_mqyxZvVmHXkQ)
[漫畫:什么是協程?](https://mp.weixin.qq.com/s/57IERpGIlvRwYCh6vSbMDA)
> 但是,yield讓協程暫停,和線程的阻塞是有本質區別的。協程的暫停完全由程序控制,線程的阻塞狀態是由操作系統內核來進行切換。
[只有程序員才能完成的小學數學作業](https://mp.weixin.qq.com/s/9LRn1J-kp86RNaXcgC2Ziw)
> 可見線程之前的切換消耗了一定的資源,所以很多情況下并非“人多好辦事”,人多所帶來的團隊協調等問題,可能會降低整個團隊的工作效率。
[百億流量系統,是如何從0開始搭建的?](https://mp.weixin.qq.com/s/zEV-7whlbOiJybh0WgSjNg)
[共享單車IOT物聯網系統是怎么設計的?](https://mp.weixin.qq.com/s/Hm2mebPz9QxWak9iT9yWPQ)
[分布式系統關注點——阻塞與非阻塞有什么區別?](https://mp.weixin.qq.com/s/nWdhFD7CL6Z1jyO5s-MiMA)
[從并發模型看 Go 的語言設計](https://mp.weixin.qq.com/s/vBUBkecD6TxSHhZja9Ww7g)
* * * * *
### 同步 & 異步
同步與異步重要的區別是在于是否阻塞,以及調用結果的通知(返回)方式。
為了便于說明,我們假定:
A:調用方
B:被調用方
<pre>
調用方 & 被調用方 例子:
調用方:JS主線程setTimeout()
被調用方:匿名函數
(被調用方有可能是一個函數,有可能是一個代碼結構,閉包,表達式等等)
</pre>
**同步**
A阻塞調用B,阻塞調用的意思就是,在B為執行完并返回結果之前,A會一直處于被阻塞掛起的狀態,直至B返回結果,A才繼續向下執行。
**異步**
A非阻塞調用B,非阻塞調用的意思就是,A調用B,A不會被阻塞,在B執行完返回結果之前,A可以繼續向下執行。這個具體怎么做到的,根據不同語言的特性有不同的實現方法,比如在JS是利用事件循環實現的。
#### 特點分析
同步調用,調用方的繼續執行依賴于被調用方的返回結果。(需要調用方立即返回結果)
異步調用,調用方的繼續執行不依賴于被調用方的返回結果。(不需要調用方立即返回結果)
同步調用不能使用MQ
異步調用的可以使用MQ
>[danger] 提示:我們平常寫的普通代碼,就是自上而上的同步代碼,同步調用,一條一條的自上而下的按順序執行。
>
> 另外要注意的是,不要受編程語言所限,很多編程語言語法、調用形式不同,但是所做的事基本是相同的,編程語言只是一層外表,不要被這層外表所蒙蔽了,它們最終都會轉變為一系列的系統調用,或者是有效的指令集而已。
* * * * *
[文章]?[為什么 go 結構是有害的?](https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/)(英文)

多線程編程之中,有一種 go 結構,就是主線程之外分出一個線程,這個線程完成任務以后,再回到主線程。作者認為,這種結構是有害的。他的最精彩觀點就是:如果允許使用 go 結構,那么所有的語言功能都可以用這種結構實現,程序很快就會亂做一團。
[Docker 底層原理淺析](https://mp.weixin.qq.com/s/0jFHlWAeH5avIO2NLpTmGA)
[進程/線程切換究竟需要多少開銷?](https://mp.weixin.qq.com/s/oUkH10Bssz_oroUiGgK7Iw)
* * * * *
last update:2018-1-5 15:04:47
- 開始
- 公益
- 更好的使用看云
- 推薦書單
- 優秀資源整理
- 技術文章寫作規范
- 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 接口自動化測試指南