CPU核数与线程数有什么关系?
作为⼀名美⾷资浅爱好者,尽管⼩风哥我厨艺拙计,但依然阻挡不了我对烹饪的热爱。那⼩风哥我通常是怎么做菜的呢?
⼤厨与菜谱
你没猜错,做菜之前先去下⼀份菜谱,照着菜谱⼀步步来:起锅烧油、葱姜蒜末下锅爆⾹、倒⼊切好的⾷材、⼤⽕翻炒、加⼊适量酱油、加⼊适量盐、继续翻炒、出锅喽!这样⼀道⾊⾹味俱佳的⼩炒⼤功告成,装盘端出来拿起筷⼦⼀尝,难吃死了。⽕候有点过,酱油加的有点少,盐加多了,中餐⾥的“⽕候”以及“适量”是最为神秘的存在,可以意会不可⾔传。因此相对肯德基麦当劳之类的标准⼯业品,中餐更像是艺术。每个⼈炒出来的菜味道都不⼀样,显然嘛,每个⼈对⽕候以及适量的理解是不⼀样的。对不起,跑题了。虽然⼩风哥我厨艺不怎么样,但输厨艺不能输⽓场,有时我会⼏样⼀起来,这边炒着A菜,那边炒着B菜。也就是说,我可以同时按照两份菜谱去做饭,如果⼩风哥⾜够快,那么我可以同时炒 N 样菜。
炒菜与线程
实际上CPU和厨师⼀样,都是按照菜谱(机器指令)去执⾏某个动作,从操作系统的⾓度讲当CPU切换回⽤户态后,CPU执⾏的⼀段指令就是线程,或者说属于某个线程。这和炒菜⼀样,我可以按照菜谱抄鱼⾹⾁
丝,那么炒菜时这就是鱼⾹⾁丝线程;我可以按照菜谱抄宫保鸡丁,那么炒菜时这就是宫保鸡丁线程。厨师个数就好⽐CPU核⼼数,炒菜的样数就好⽐线程数,这时我问你,你觉得厨师的个数和可以同时抄⼏样菜有关系吗?答案当然是没有。CPU的核⼼数和线程个数没有什么必然的关系。单个核⼼上可以跑任意多个线程,只要你的内存够就⾏;计算机系统内也可以有任意多核数,只要你有钱就⾏。看到这个答案你是不是觉得有点疑惑、有点疑问、有点不明所以,这好像和其它⼈说的不⼀样啊!别着急,我们慢慢讲。
傻傻的CPU
CPU根本不理解⾃⼰执⾏的指令属于哪个线程,CPU也不需要理解这些,CPU需要做的事情就是根据PC寄存器中的地址从内存中取出后执⾏,其它没了。你看CPU才不管你系统内有多少线程。有多少线程是谁需要来关⼼的呢?是操作系统。线程是操作系统的把戏。
操作系统与多任务
很久很久以前,计算机⼀次只能执⾏⼀个任务,你不能像现在这样在计算机上⼀边看电影⼀边在下⼩电影,哦,不对,⼀边写代码,⼀边下载资料。要么你先写代码,写完代码后再去下资料,要么你先下资料然后再写代码,总之,这两个任务不能同时进⾏。这显然很不⽅便,就这样,多任务——Multi-Tasking,诞⽣了。你CPU不是只知道执⾏机器指令吗?很好,那作系统就通过修改你的PC寄存器,
让你CPU 执⾏A任务的机器指令⼀段时间,然后下⼀段时间再去执⾏B任务的机器指令,再然后下⼀个时间段去执⾏C任务的机器指令,由于每⼀段时间⾮常少,通常在毫秒级别,那么在⼈类看来A、B、C三个任务在“同时”运⾏。这就是多任务的本质。
进程与线程
CPU不知道执⾏的某⼀段机器指令属于A任务还是B任务,只有操作系统知道,同时操作系统还能知道任务A和B任务是否属于同⼀个地址空间。如果属于同⼀个地址空间,那么任务A和任务B就是我们熟悉的“多线程”;如果不属于同⼀个地址空间,那么任务A和任务B就是我们熟悉的“多进程”,现在你应该明⽩这两个概念了吧。这⾥出现了⼀个有点拗⼝的名词,地址空间,Address Space,关于地址空间的概念以及进程线程这⼀部分更加详细的讲解,请参考⼩风哥的《深⼊理解操作系统》第7章,关注"码农的荒岛求⽣"并回复”操作系统“即可。值得注意的是,计算机系统还在单核时代就已经有多线程的概念了,我们之前说过,即使是单核也可以执⾏多个线程,那么有的同学可能会有疑问,在单核的系统中开启多个线程有什么意义吗?
单核与多线程
假设现在有两个任务,任务A和任务B,每个任务需要的计算时间都是5分钟,那么⽆论是任务A和任务B串⾏执⾏还是放到两个线程中并⾏执⾏,在单核环境下执⾏完这两个任务总需要10分钟,因此有的同学
觉得单核下多线程没什么⽤。实际上,线程这个概念为程序员提供了⼀种编程抽象,我们可以把⼀项任务进⾏划分,然后把每⼀个⼦任务放到⼀个个线程中去运⾏。假如你的程序带有图形界⾯,某个UI元素背后需要的⼤量运算,这时为了防⽌执⾏该运算时UI产⽣卡顿,那么可以把这个运算任务放到⼀个单独的线程中去。因此如果你的⽬的是防⽌当前线程因执⾏某项操作⽽不得不等待,那么在这样的应⽤场景下,你根本就不需要关⼼系统内是单核还是多核以及有多少个核。
阻塞式I/O
这也是使⽤线程的经典场景。如果没有线程,那么执⾏阻塞式I/O时整个进程会被操作系统暂停,但如果你开启两个线程,其中⼀个线程被阻塞时另⼀个线程依然可以继续向前推进。这样的话你就不需要去使⽤反⼈类的异步IO了。当然,这⼀切的前提是你的场景不涉及⾼性能以及⾼并发,如果涉及的话那这就是另⼀个话题了,如果你想了解这⼀话题,关注“码农的荒岛求⽣”并回复“⾼并发”即可。在这种简单的场景下,你创建线程时也不需要关⼼系统中是单核还是多核。
多核时代
421事件是什么实际上,线程这个概念是从2003年左右才开始流⾏的,为什么?因为这⼀时期,多核时代到来了。之所以产⽣多核,是因为单核的性能提升越来越困难了。尽管采⽤多进程也可以充分利⽤多核,但毕竟多进程编程是很繁琐的,这涉及复杂的进程间通信机制、进程间切换的较⾼性能损耗、进程间内存相互隔离
带来的对内存消耗等。线程这个概念很好的解决了上述问题,开始成为多核时代的主⾓,要想充分利⽤多核资源,线程是程序员的⾸选⼯具。
真正的并⾏
有了多核后,运⾏在两个线程中的任务A和任务B实现了真正的并⾏。此前这样⼀句话⼴为引⽤,这句话是这么说的:threads are for people who can't program state machines
“线程是为那些不懂状态机的⼈准备的”,这句话在单核时代有它的道理,因为在单核时代,所有的任务都不是在同时向前推进,⽽是“交错”前进,A前进⼀点,然后B前进⼀点,线程并不是实现这种“伪并⾏”唯⼀的⽅法,状态机也可以。但在多核时代,这句话就不再适⽤了,对于⼤多数程序员来说多进程多线程⼏乎是充分利⽤多核资源的唯⼀⽅法。如果你的场景是想充分利⽤多核,那么这时你的确需要知道系统内有多少核数,⼀般来说你创建的线程数需要与核数保持线性关系。也就是说,如果你的核数翻倍,那么创建的线程数也要翻倍。
需要多少线程?值得注意的是,线程不是越多越好。如果你的线程是不涉及任何I/O、没有任何同步互斥之类的纯计算类型,那么每个核⼼⼀个线程通常是最佳选择。但通常来说,线程都需要⼀定的I/O,可能需要⼀定的同步互斥,那么这时适当增加线程可能会提⾼性能,但当线程数量到达⼀个临界值后性能开始下降,这时线程间切换的开销将显著增加。这⾥之所以⽤适当这个词,是因为这很难去量化,只能⽤
你实际的程序根据真正的场景进⾏测试才能得到这个值。
总结
线程数和CPU核⼼数可以没有任何关联,如果在使⽤线程时仅仅针对上述提到的⼏个简单场景,那么你根本不需要关⼼CPU是单核还是多核。但当你需要利⽤线程充分发挥多核威⼒时,通常情况下你创建的线程数与核数要保持⼀种线性关系,最佳系数通常需要测试才能得到。我是⼩风哥,希望这篇⽂章对⼤家理解多核以及多线程有所帮助。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论