💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 多进程/多线程 ### 前言 ![](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&timestamp=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&timestamp=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&timestamp=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