关于线程和进程的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ben548
V2EX    PHP

关于线程和进程的疑问

  •  
  •   ben548 2015-12-18 11:19:00 +08:00 5268 次点击
    这是一个创建于 3587 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前在做 php 的开发时从来没有想过线程的问题(野生程序员的悲哀),最近在看朴灵写的《深入浅出 nodejs 》时,第九章提到了进程和线程。

    1 、对于这两个概念我一直很模糊,在网上查到的资料是阮一峰写的一篇文章,他把一个进程比作一间工厂,一个线程比作工厂里面的工人,那么是不是可以这么理解,一个进程可以包含多个线程,开启多进程主要是为了实现多 cpu 的最大利用化呢?

    2 、还有我了解到 php 是不支持多线程的,那么在多人访问网站的情况下不是会造成阻塞吗?但是事实上我们在浏览网站的时候好像并没有什么阻塞的情况发生啊?是因为 apache 做了什么吗?/p>

    3 、另外 apache 和 nginx 处理 php 请求上有什么区别呢?为什么现在的网站都趋向于使用 nginx ,而不是 apache ,我对这两者的理解,只有 apache 是通过模块调用的方式来处理 php 请求的,而 nginx 则是将 php 请求转发到了 php-fastcgi 上面。

    31 条回复    2015-12-19 10:50:06 +08:00
    cxe2v
        1
    cxe2v  
       2015-12-18 11:28:06 +08:00
    1.多进程并行需要多个 CPU 核心同时处理才能体现优势,但线程的优点不止这个
    2.你猜对了,是 apache 做了些什么,简略的说就是来一个请求, apache 就开一个线程来处理
    3.我不知道
    shippo7
        2
    shippo7  
       2015-12-18 11:34:30 +08:00
    一个程序运行时至少要有一个进程,一个进程可以包含多个线程

    多个线程之间可以通信(使用共享内存),使得多线程可以处理同一个任务。例如使用多个线程压制影片。

    多个进程之间不可以直接通信(使用独立内存地址),例如开两个 VLC 播放器窗口播放不同影片,还有 Chrome 的每个标签页使用独立进程。
    ben548
        3
    ben548  
    OP
       2015-12-18 11:43:51 +08:00
    @shippo7 Chrome 的每个标签页使用独立进程? 按照我的理解,是不是一个 cpu 只能开一个进程呢?如果是的话,那么 chrome 的标签页的数量是有限制的?是不是我理解错了呢
    mthli
        4
    mthli  
       2015-12-18 11:47:43 +08:00
    @ben548 可以去了解一下 CPU 的任务调度。并不是说一个 CPU 只能开一个进程的。
    mahone3297
        5
    mahone3297  
       2015-12-18 11:48:12 +08:00
    @ben548 1 个 cpu 怎么会只能开 1 个进程?
    那单核的机器,不都只能运行 1 个进程了?
    系统起来,就有很多进程了。。。大家按时间片切换去使用 cpu ,同一时间, 1 个核只能处理 1 个进程,应该是这样。
    akira
        6
    akira  
       2015-12-18 11:48:45 +08:00
    @ben548 理解有偏差。 cpu 数和进程数没有关系。
    huhao
        7
    huhao  
       span class="ago" title="2015-12-18 11:48:59 +08:00">2015-12-18 11:48:59 +08:00
    楼主既然已经有了线程和进程的疑问了,说明已经到了一个阶段了,那么在这个阶段下,我个人建议先不要去看 nodejs 这种,先去学一门强类型的语言,比如 C 和 JAVA ,然后再去翻一翻操作系统概念或 CSAPP 之类的书,总结一下就是,可以开始去通底层了
    shippo7
        8
    shippo7  
       2015-12-18 11:49:28 +08:00
    @ben548 CPU 的多任务机制允许一个 CPU 核心运行多个进程。最早的 DOS 系统是单任务,也就是一个 CPU 运行一个进程。现代操作系统允许多个进程轮流使用 CPU 时间,每个进程使用 CPU 的时间很短,每个进程从等待队列被放入 CPU 中运行,然后再进入等待队列,直到一个进程的任务结束。这就是打开 Windows 任务管理器,可以看到几十个进程同时运行的原因。
    xylophone21
        9
    xylophone21  
       2015-12-18 11:49:44 +08:00
    都是多条线“同时”跑,你可以简单的理解成多个入口函数并行的在运行。

    但线程是共享内存地址空间的,也就是说 A 线程里的一个变量, B 线程可以直接拿来用。

    进程的的内存地址空间是隔离的,也就是说即使同一个变量,也是各用各的,互不影响。如果一定要影响,就需要特殊的手法。
    mthli
        10
    mthli  
       2015-12-18 11:49:51 +08:00
    @ben548 好像之前我这么说也不太准确。总之和至少和(操作系统的)任务调度有关了。
    shippo7
        11
    shippo7  
       2015-12-18 11:54:49 +08:00
    关于线程与进程的问题,建议看《操作系统概念》这本书
    MForever78
        12
    MForever78  
       2015-12-18 12:57:55 +08:00   2
    @shippo7 说得对,要想深入了解,《操作系统概念》这本书才是正解。阮一峰写的那篇文章举工厂的例子来尝试说明进程和线程,对懂的人来说很好理解,如果本来就什么都不明白的话看了还是不知所云。

    不过因为正好刚学过,我尝试解释一下。进程是指正在运行的一个程序,不仅仅包含这个程序的代码( code ),数据( data ),文件,还包括当前的运行状态,即指令( Program Counter ),栈,和当前 CPU 寄存器的值(有时还包括堆)。新创建一个进程需要在内存中创建以上所有内容。对于 Web Server 来说,服务不同连接的代码、数据、文件都是相同的,只是运行状态不同。所以对每个连接都重新创建进程会造成资源浪费。

    而线程基本上就是对进程的代码、数据、文件进行重用,每个线程只是保存了不同的运行状态。于是节省了资源。

    另一方面,单个 CPU 同一时间只能执行一条指令,即只能运行一个进程。为了让系统能「看起来」在同时进行多个进程, CPU 需要不断地在进程之间切换。这就是 Multiprogramming 的概念。而进行进程切换的时候不但需要把 CPU 的当前指令指针( Program Counter )切换到下一个进程,并且需要保存当前进程的运行状态,载入下一个进程上次被中断时的运行状态。这部分时间其实 CPU 是没有做什么对程序来说有意义的事情的,称为进程切换的开销( Overhead )。

    线程之间的切换代价要小于进程之间的切换代价,因此使用线程节省了时间。
    liuxu
        13
    liuxu  
       2015-12-18 13:09:25 +08:00
    进程是从系统拿资源,线程从进程中拿资源。
    mitoop
        14
    mitoop  
       2015-12-18 13:16:18 +08:00
    最近也在思考这个问题,看来非要操作系统概念来一下了
    ryd994
        15
    ryd994  
       2015-12-18 13:17:48 +08:00 via Android
    @MForever78 其实上因为虚拟内存,多个进程之间,代码和文件也是可以做到不影响性能的共享的。特别是 Linux 下 fork 是 cow 的,浪费更是相当小。所以多进程相比多线程的好处,主要还是在内存隔离。
    BOYPT
        16
    BOYPT  
       2015-12-18 13:23:53 +08:00
    多进程多线程,实质上是任务调度方式。具体要看在什么环境下讨论,事实上上面说的很多线程、进程的特点,在特定环境下都存在特殊情况,特别在 linux 环境下,线程进程的区别非常小。

    在 PHP 范畴,如果是指 PHP 做 web 的,因为前端的 apache/nginx 的多线程 /多进程 /异步模型已经封装好了这些需要并发的过程,到达你的 php 代码时候,只是需要 php 完成最后的实际任务而已,所以 php 不需要多线程。

    PHP 除了做 web 以外,其实还可以做桌面应用的,只是比较少见,比如用 php-gtk 写图形界面,那就得在 php 内调用线程库接口来实现多线程了,因而也不能说 php 没有多线程,实质上有没有多线程跟语言本身关系不是很大,因为不管什么语言,最终都成为操作系统里面一个进程,调用是操作系统的 api 。
    wy315700
        17
    wy315700  
       2015-12-18 13:28:14 +08:00
    深入理解计算机系统 推荐看这本书
    ben548
        18
    ben548  
    OP
       2015-12-18 13:45:43 +08:00
    @BOYPT 因为前端的 apache/nginx 的多线程 /多进程 /异步模型已经封装好了这些需要并发的过程 并不完全认同你的看法,如果真的 apache 和 nginx 处理了并发的过程,那边我们为什么在程序开发的过程中需要考虑并发的问题,比如说秒杀等功能的实现?需要用到队列和锁等机制
    JmmBite
        19
    JmmBite  
       2015-12-18 13:54:57 +08:00
    公路的 “单向单车道” 与 “单向多车道”的区别。
    队列就是公路收费口。
    iyaozhen
        20
    iyaozhen  
       2015-12-18 13:58:12 +08:00
    试着回答一下:
    1 、可以这么理解,一个进程可以有很多线程。多进程可以很好的利用 CPU 。

    2 、 3 、是的, Apache 和 Nginx 做了很多事情。
    Apache+php_module 是父进程+子进程的模式,每个访问请求会生成子进程,就不会有阻塞了。
    Nginx+PHP-FPM 的话感觉 Nginx 和 PHP 相互独立了, Nginx 遇到自己处理不了的请求就会给 PHP-FPM ( PHP FastCGI 管理器)处理,每来一个请求就会交给一个子进程去处理(这里根据 PHP 的运行配置不同效果也不同,子进程的数量可以是固定的也可以动态生成),然后 Nginx 对交给 PHP-FPM 进行轮训( epoll 机制)。这样处理性能和资源占用都比 Apache 有优势。

    楼主可能也对 PHP MySQL 持久连接感兴趣: https://iyaozhen.com/php-mysql_pconnect-discuss.html (硬 SEO )
    iyaozhen
        21
    iyaozhen  
       2015-12-18 14:01:44 +08:00
    @ben548 这里的并发应该是竞争问题了吧。现在的系统能保证大家都能进来抢东西,但东西只有一个所以要排个队啥的。很可能你排上队了最后还是没有得到
    BOYPT
        22
    BOYPT  
       2015-12-18 14:07:29 +08:00
    @ben548 因为你这是跟数据库打交道,前面说 apache/nginx 封装处理的,是 tcp 链接到 php 的输出输入部分的并发,至于你的代码去数据里面的并发,当然你自己处理了。
    ben548
        23
    ben548  
    OP
       2015-12-18 14:17:49 +08:00
    @BOYPT 恩,理解了,谢谢各位的热心回答
    MForever78
        24
    MForever78  
       2015-12-18 14:35:41 +08:00
    @ryd994 是的,这里为了说明主要矛盾忽略了其他的优化和细节。
    inevermore
        25
    inevermore  
       2015-12-18 14:46:30 +08:00   1
    @huhao C 是弱类型,你把强弱和静态动态搞混了。。
    neoblackcap
        26
    neoblackcap  
       2015-12-18 15:08:07 +08:00
    @ryd994 这个还说不上是优点,因为 IPC 其中就有一个说共享内存,这个是线程的优势。大概这是两者的不同吧,不能简单地说优点还是缺点,毕竟有的时候就是需要内存不隔离。
    ryd994
        27
    ryd994  
       2015-12-18 20:20:02 +08:00
    @neoblackcap 优点缺点相对的嘛。进程的优点似乎也就剩这个了。
    julyclyde
        28
    julyclyde  
       2015-12-18 23:39:22 +08:00
    技术话题是很简单明了的
    看了 ruanyf 的比喻,我反倒不懂了
    neoblackcap
        29
    neoblackcap  
       2015-12-18 23:43:45 +08:00
    @ryd994 是啊,最直观的感觉就是创建线程的成本更低。其实很多时候是需要看场景的,脱离场景说优缺点,实在没办法。
    SoloCompany
        30
    SoloCompany  
       2015-12-19 00:14:51 +08:00
    仅对于多任务而言,线程和进程的区别基本上可以忽略
    最大的区别在于内存管理上的差异

    单进程多线程因为有共享内存因而可以有真正意义的 session 以及缓存
    但是因为需要访问共享内存,必须考虑锁和并发,程序编写会比较复杂

    多进程单线程没有共享内存,所以 session 和缓存都只能依靠外部进程或文件系统
    但因为没有共享内存,程序编写不需要考虑锁和并发也更加简单

    php 语言本身就不支持多线程,也用不到共享内存,所以两种模型可以说毫无差异
    zjqzxc
        31
    zjqzxc  
       2015-12-19 10:50:06 +08:00
    只说说问题 3 :
    nginx+php ; nginx+Apache+php ; apache+php
    以上三种方式楼主可以自己搭建然后 ab 命令测试一下; apache 要做相应优化,要不更惨
    从左到右性能依次降低

    至于为啥楼上已经有人说得很清楚。。我就一句话,同配置下 nginx+php 能承受更大负载。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2975 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 13:26 PVG 21:26 LAX 06:26 JFK 09:26
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86