对于单核 cpu 而言,开多线程的目的难倒只能是为了防止阻塞么? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
aiqier
V2EX    程序员

对于单核 cpu 而言,开多线程的目的难倒只能是为了防止阻塞么?

  •  
  •   aiqier 2015 年 11 月 11 日 14557 次点击
    这是一个创建于 3713 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以下是一些单核 cpu 多线程的疑问,求解答(都指单核)。
    1.如果一个进程有 n 个任务要处理,因为终究是在一个 cpu 上跑,所以这 n 个任务在一个线程还是多个线程上跑,执行的总时间是一样的(多线程,线程切换可能更浪费时间)?
    2.是否进程开多线程就能抢到更多的 cpu 时间, python 这种带 GIL 的估计是没戏了,那么 java 呢?
    3.自己抢到更多 cpu ,机器上的其它程序不就 cpu 时间少了么?是因为 cpu 大部分时间都是空闲的,不怕抢?还是因为在做应用层开发的时候,是不用考虑其它程序能不能抢到 cpu 时间的。
    4.一个进程所有线程能抢到的时间片总和是有最大值吗?一个线程一次能拿到多长的 cpu 时间?
    综上,我的最大疑问就是:对于单核 cpu 而言,开多线程难倒只能防止阻塞么?

    34 条回复    2015-11-14 18:00:05 +08:00
    Oi0Ydz26h9NkGCIz
        1
    Oi0Ydz26h9NkGCIz  
       2015 年 11 月 11 日
    我也有这疑惑,不知单核 cpu 跑程序编译时要不要开启多线程。
    kamushin
        2
    kamushin  
       2015 年 11 月 11 日
    写个应用程序, 就准备跑在单核上?
    feikaras
        3
    feikaras  
       2015 年 11 月 11 日
    为什么用 python , java 那么慢的语言却在操心操作系统的调度开支?
    pythonee
        4
    pythonee  
       2015 年 11 月 11 日
    吞吐量
    webflier
        5
    webflier  
       2015 年 11 月 11 日   1
    通常一个任务不光 cpu 上要花时间, io 上也要花时间(不如去数据库查数据,去抓网页登)。
    一个进程在等 io 的时候, cpu 是闲置的,另一个进程正好可以利用 cpu 把 cpu 该做的事做完。
    多几个进程一起跑,可以把 io 和 cpu 都跑满了。
    大概就是这个意思
    br00k
        6
    br00k  
       2015 年 11 月 11 日
    充分利用 CPU 空闲啊。超线程技术也是一样。
    Ouyangan
        7
    Ouyangan  
       2015 年 11 月 11 日
    @feikaras java 不慢了....
    jonah
        8
    jonah  
       2015 年 11 月 11 日 via Android
    如果自己实现任务 A 阻塞时去运行 B ,效率有可能比多线程要高,多线程就是把这种调度转交给了操作系统。而且还有设计和逻辑上的便利,比如一个线程负责一个不同类型的工作。
    ryd994
        9
    ryd994  
       2015 年 11 月 11 日
    看是什么认为。如果完全是 cpu ,开多线程只会更慢。上下文切换的开销。
    抢 CPU 时间前提是同一优先级。如果其他进程优先级高,那怎么抢都抢不到。

    @jonah 这不就是协程么
    lzhip
        10
    lzhip  
       2015 年 11 月 11 日   1
    1 、不一定,多线程可以在 io 的时候切换到其他线程执行。如果单线程那就只能等了。
    2 、一般是的,一个要看你线程的操作。一般你在单核机器上写一个死循环,基本整个机器都卡了。但是如果你起下次一百个线程都是 sleep ,那也不会太占用 cpu 。另外操作系统调度线程不依赖进程。
    3 、当然要考虑啊!要不把用户机器卡死了,人家就不用你的程序了。
    4 、看什么平台吧, windows 好像不支持抢占。线程只能被系统调用。
    chairuosen
        11
    chairuosen  
       2015 年 11 月 11 日   2
    xuyinan503
        12
    xuyinan503  
       2015 年 11 月 11 日
    真是 iV2ex 啊,这都能黑到 windows
    aalska
        13
    aalska  
       2015 年 11 月 11 日


    这图不错
    HentaiMew
        14
    HentaiMew  
       2015 年 11 月 11 日
    @feikaras java 早就不是黑执行效率了,它在有 GC 功能语言中已经算足够快的了。 Java 该黑的是它的内存消耗....
    yuelang85
        15
    yuelang85  
       2015 年 11 月 11 日
    是的,就是为了防止堵塞。
    Oi0Ydz26h9NkGCIz
        16
    Oi0Ydz26h9NkGCIz  
       2015 年 11 月 11 日
    @chairuosen 神了,这是奔腾 D 吗
    Codist
        17
    Codist  
       2015 年 11 月 11 日   1
    1 、如果一个进程执行 N 个任务,而这些任务又属于 I/O 型的任务,通过 CPU 的调度是可以提高效率的,通常网络 I/O 阻塞的时间比线程 context switch 的时间要长多了。
    2 、在 Linux 下线程进程的调度策略相同,如果一个进程中包含更多线程的话,我猜会拿到更多的执行时间。 CPython 的 GIL 只是给多线程的执行加了锁,限制了多线程的并行执行,单核下 GIL 应该就跟没有一样。
    3 、 CPU 的计算速度太快了,进程的调度已经比较完善,通常应用层面程序不需要考虑底层进程的调度对程序的影响,但是要考虑程序 CPU 资源的消耗,写一个死循环跑一会儿 CPU 都能煎鸡蛋了。
    大多数情况下 CPU 的计算都是不饱和的,通常服务器 CPU 利用率达到 80%的时候就要扩容了。
    4 、没有听过类似这种限制,太细的东西不清楚。
    开多线程并一定是为了性能,很多场景下你的业务逻辑是并发的,所以你的程序逻辑也是并发的。
    congeec
        18
    congeec  
       2015 年 11 月 11 日
    你说的是系统级的线程还是 CPU 级的线程?照你的描述,你想表达的是多进程。一句话,单核 CPU 没法跑系统级的多进程。单核多线程主要是为了增加 I/O 利用率。如果有支持超线程技术(HT)的单核 CPU ,请告诉我。
    线程的概念其实有些模糊,比如: CPU 级线程就是操作系统级进程。程序自己也可以把系统级线程看做进程,并自己实现多线程。这种程序自己实现的多线程就是所谓的协程(coroutine)或纤程(fiber thread)。
    adadada
        19
    adadada  
       2015 年 11 月 11 日
    @congeec 这里的“系统级的多进程”指的是操作系统内核实现的进程还是 CPU 的 HW Thread ?如果是前者,操作系统的还是可以实现多进程的啊?只是这样的多进程只具备 currency 而不具备 parallelism 。
    leavic
        20
    leavic  
       2015 年 11 月 12 日   1
    我仅仅从一个 5 年单片机码农所理解的角度回答一下这些问题:

    1.如果一个进程有 n 个任务要处理,因为终究是在一个 cpu 上跑,所以这 n 个任务在一个线程还是多个线程上跑,执行的总时间是一样的(多线程,线程切换可能更浪费时间)?

    A :对于单核 CPU 来说,所谓的线程,就是 task , CPU 就是依靠调度器在这 N 个 task 之间来回切换,同一时刻只有一个 task 在运作。

    2.是否进程开多线程就能抢到更多的 cpu 时间, python 这种带 GIL 的估计是没戏了,那么 java 呢?

    A :这个涉及到操作系统的设计原理, windows 和 linux 本质上都不是实时系统,如何分配 CPU 时间在不同的操作系统上有不同的规则,一般来说是按优先级分配。但你一个人开了多个任务,总概率上讲分配到更多 CPU 资源的概率是更高的。
    3.自己抢到更多 cpu ,机器上的其它程序不就 cpu 时间少了么?是因为 cpu 大部分时间都是空闲的,不怕抢?还是因为在做应用层开发的时候,是不用考虑其它程序能不能抢到 cpu 时间的。

    A:这个取决于你应用到底能 CPU 密集到什么程度,对一般的应用来说,你是不需要担心别的程序没有 CPU 资源可用的,唯一需要注意的是避免进入死循环,在单片机中,中断里出现一个死循环的结果就是占用全部 CPU 资源。

    4.一个进程所有线程能抢到的时间片总和是有最大值吗?一个线程一次能拿到多长的 cpu 时间?
    综上,我的最大疑问就是:对于单核 cpu 而言,开多线程难倒只能防止阻塞么?

    A :这个依然取决于操作系统的设计。对于单核 CPU 而言,多线程是几乎唯一合理的利用 CPU 资源的方式,一颗 CPU 如果只有一个线程,那基本就是个弱智级别的 CPU 。
    congeec
        21
    congeec  
       2015 年 11 月 12 日 via iPhone
    @adadafa 抱歉还是没说清楚。用单核 cpu 的系统不可能有真正的多进程,虽然咱可以调用多进程 API ,但那是假的。楼上也说了,现在 cpu 是靠分配时间来分配资源,在切换( switch )到另一个任务( task )的时候,上一个任务的上下文) context )要保留下来,如此往复。这和线程有什么区别?所以,所谓的进程、线程、协程都是线程(thread), 一层套一层。明白人为了区分他们搞出来一大堆新术语,结果大家更迷了。你说的最后一句很对,单核只有 concurrency ,没有 parallelism 。可以去搜搜 Linus 为什么喷“ parallel 浪费大家时间”。
    sgissb1
        22
    sgissb1  
       2015 年 11 月 12 日   1
    LZ ,你没有完全理解多线程的意义。或者没有完全理解什么是多线程,包括现在很多写代码的人,总在说多线程,有时候甚至把多线程和多并发或者多线程和多吞吐处理给混为一谈。

    首先说一下一个进程里面为何要开多线程问题,和 cpu 是否多核,或者主板是否多路 cpu 关系是有的,但也是有限定条件的,具体内容如下:

    1 ,由于部分 api 不支持异步方式执行,仅仅支持同步执行。例如读取一个文件,当每次读取的文件的数据很大时,内存缓存中没有足够的内存提交给调用者,这时 api 或者操作系统会代用户去从磁盘上读取文件,而磁盘相对于内存和 cache 来说属于慢速设备,并且在操作系统调度层面,对于此类操作是,现成被阻塞住(即挂起),然后转为执行其他任务。
    为了让整个进程不进入假死(僵死)情况,需要在开一个线程来维持其他任务的执行。

    2 ,在多路 cpu 的系统中,多线程可以提高任务处理的效率。即理想情况下,每个线程独占一路 cpu 处理能。

    3 ,特殊多路系统,在非对称多路系统中,每个线程(进程)都执行在不同的核上,所访问的硬件资源不同,所以需要开多个线程。

    至于你说的抢 cpu 执行时间问题,要分操作系统看,目前我们常用的 windows 和 linux 都是抢占式操作系统。对于 linux 我不是很熟,对 windows 略知一二:

    1 ,操作系统调度粒度是线程+进程。即操作系统调度的最小单位是线程,但是否决定该线程执行,除了看线程执行时间和未执行间隔以外,还需要看总进程内的执行情况。
    其中还存在进线程优先级问题,中断优先级, cpu 执行平衡问题,就近执行原则等。

    2 ,一个进程中,线程并非越开越多就好。因为非分时的非实时操作系统的任务调度周期很有可能是不准的,操作系统是否要打断一个线程的执行,转而交给另外一个线程执行,除了调度周期到来的调度扫描,还有任务执行的优先级, IRQL 级别,线程处于什么状态等。

    3 ,过多的线程不仅不能抢到有效的 cpu 执行时间,还会导致线程环境切换的浪费。因为每次线程的切换其中伴随的态转换,以及堆栈移动、寄存器恢复、内存调度等问题。频繁切换线程,只会得不偿失,不管是 python 或者 java 或者 c++或者 c#都是一样的,因为是操作系统在管理线程执行。

    至于你提出的第四个疑问,在单核 cpu 里面开多线程的事情。我只能和你说,设计决定一切。
    theoractice
        23
    theoractice  
       2015 年 11 月 12 日 via Android
    单核纯计算不要开多线程。有 io 的话性能瓶颈可能不在 cpu 上。参考 amdahl 定律。
    br00k
        24
    br00k  
       2015 年 11 月 12 日 via Android
    @congeec P4 就有单核超线程。 MIPS 产品也有,有些架构还有单核四线程或更多的。
    congeec
        25
    congeec  
       2015 年 11 月 12 日 via iPhone
    @br00k 涨姿势了,谢谢。:D
    zhangdawei
        26
    zhangdawei  
       2015 年 11 月 12 日
    CPU 快, IO 慢,不多线程, CPU 效率不高,操作系统效率也不高。
    aiqier
        27
    aiqier  
    OP
       2015 年 11 月 12 日
    @chairuosen 这什么意思。。。大多程序只跑一个核?
    aiqier
        28
    aiqier  
    OP
       2015 年 11 月 12 日
    @Codist 感谢, 最后一句是“并不一定”么?
    aiqier
        29
    aiqier  
    OP
       2015 年 11 月 12 日
    @sgissb1 那么是不是说,瓶颈如果是 io ,使用异步 io ,比如 nodejs , nginx , epoll ,之流比多线程更合适?
    yuchting
        30
    yuchting  
       2015 年 11 月 12 日
    @sgissb1
    @leavic
    两位说的很清楚了。感觉楼主把多线程和多核搞混了,把操作系统和执行程序搞混了。这个可能和和市面上的多核宣传有关系吧,多核就可以一边看电影一边压缩文件之类的宣传,然后把单核或者少核鄙视一把,让人们更新换代,增加自己的销量。
    还有一个叫多任务的概念,是对比以前 DOS 系统的单任务,也是宣传。
    计算机科学貌似在很早很早的时候,就进行了时分多任务的改进了,和多核没关系,唯一的目的就是让 cpu 的空闲时间变少(等待用户操作,等待网络、磁盘等输入输出设备 io)。
    而这个改进是操作系统完成的,和硬件关系相对较少。如果真的有兴趣想理解计算机,操作系统和编译原理的基础知识必不可少。
    说完了。
    sgissb1
        31
    sgissb1  
       2015 年 11 月 12 日
    @aiqier 兄弟,你的代码功底还有待加强。你问的这个问题,我没法给你答复。

    我说了设计决定一切
    Codist
        32
    Codist  
       2015 年 11 月 12 日 via Android
    @aiqier 噢,是
    SIFT2009
        33
    SIFT2009  
       2015 年 11 月 12 日
    单核要跑多线程,有多大意义?
    kaneg
        34
    kaneg  
       2015 年 11 月 14 日 via iPhone
    多线程对 GUI 程序非常有用,因为没有多线程支持, Javascript 要实现一个 并行的任务有多难
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1018 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 23:30 PVG 07:30 LAX 15:30 JFK 18:30
    Do have faith in what you're doing.
    ubao msn 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