## 多进程/多线程
### 前言
![](http://cdn.aipin100.cn/17-10-9/66029542.jpg)
<p class="img-desc">这图够形象吧</p>
// ![img](https://p3a.pstatp.com/weili/l/79054104370036923.webp)
程序分为两种,`单进程/单线程` 和 `多进程/多线程` 两种。
(为了方便,下文以“单”代指 `单进程/单线程` ,“多”代指 `多进程/多线程` )。
“单”程序不用考虑并发问题(比如浏览器中的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笔记 · 看云](https://www.kancloud.cn/xiak/php-node/356621)
[定时-时钟-阻塞 · php笔记 · 看云](https://www.kancloud.cn/xiak/php-node/400090)
[多进程/多线程 · php笔记 · 看云](https://www.kancloud.cn/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/)(英文)
![](https://www.wangbase.com/blogimg/asset/201805/bg2018051811.png)
多线程编程之中,有一种 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 接口自动化测试指南