转:[线程原理]为什么脚本语言大多数是单线程的?汇编语言,C java python go CPU多核心利用率解析
最近终于搞懂了线程的概念,①任何一个CPU的单位时间内,只能做一件事,一般是指令集内的一个指令(参考汇编指令集)
②性能越强的CPU,单位时间可以做的越短
于是,在任何一秒内,CPU可以被抽象成这样
如果CPU性能越强,则格子会越密集。其中每个格子代表单位CPU时间,如果为空代表这个单位时间
CPU什么事都没做(就像汇编中的nop)
现代CPU因为频率无法做的更高,大多数采用多核心多线程技术,实际上就是多加几个CPU单元,
体现在上表就是列的数量变多。
——————————————————————————
假设有一个单线程程序,按照我们以往的编程经验,它在4线程CPU的平台上最多也只能占CPU的25%。
这就在上表体现出了,几乎一个线程的所有格子都被占用了。
但是为什么不能把整个表占满呢?
这就是问题关键所在。
我们以Node.js为例(这里要注意一点,并非是Javascript这个语言不支持多线程,而是运行JS平台的Node不支持多线程,你完全可以写一个支持多线程的JS平台)
Node.js从设计开始,就继承了浏览器JS的设计,即任何时刻只做一件事,这使得资源管理(如硬盘、内存)变得不会繁琐,如果同时做很多事,这些资源就要互相加锁,互斥。因为大多数脚本语言考虑的轻量性、便捷性,从设计开始就干脆不考虑,如浏览器JS,资源是显示在屏幕上的dom组件,如果同时有两个线程发出了修改这个dom的请求,CPU该听谁的?基于这种运行环境的考虑,干脆就直接单线程,这样就不用考虑资源的锁了。(关于node的事件循环,即event-loop,以后再谈,与本篇关系不大)
这段话有一句是关键句:任何时刻只做一件事。
这代表了上表,任何一行只能出现一格是黄色。
所以你可能会想,既然有cpu有四个线程,强制利用上不行吗:
强制利用上会是这样的:
所以无论怎样,只要有这个限制在,CPU永远只能利用25%。
————————————————
提升CPU单核性能,即可以让上述表格更加密集,但成本是昂贵的。
于是大多数大型项目,都会使用多线程编程。
例如java(自带封装好的Thread类),C(可以使用winapi的CreateThread)
那么像node、python(也是单线程语言平台),就没有解决办法了吗?
答案是,有。
只要你能处理好资源的调用,即同一时间"一定"不能发生两次的对同一资源的使用,那么你可以安全的使用线程来
加速计算。或者说,对CPU资源的利用率。
但是在脚本语言中,并不存在创建线程的接口(实际上,你仍然有办法调用系统API强制创建线程,这里暂不讨论,我们应当利用语言本身自带的东西实现)
大多数脚本语言都会有一个内置(built-in)的模块,子进程!
(python中是multiprocessing,node.js中是child_process)
可以这样理解:
黄色代表进程1,蓝色代表进程2,1秒内的CPU时间利用情况。
这时候你可以看到,一行已经有两个CPU事件,所以你仍然要调度资源的分配。
所以我这里直接抛砖引玉的提出解决的方案。
利用IPC(进程间通信),IPC有好几种办法,一种是套接字通信(TCP、UDP),jigsaw就是一种udp进程间通信的解决方案。另一种,也是最快的一种:shared memory(内存共享),因为进程跑在同一个机器上,所以它们可以划分一段区域规定好协议,用来通信、资源管理等。
选择好IPC方式后,像线程池一样,你仍然可以设计一个进程池,来统一管理这些子进程(worker)能够利用的资源和闲置、繁忙情况,然后往这个池子里丢任务就行了。
实测,利用jigsaw来实现IPC通信延迟在10ms左右,对于普通业务(如物联网,大型网站后端)完全可以胜任,但是对于游戏级别的,例如你想设计一个超级游戏服务端,能够承载上千人一起今晚八点征战沙城(,这么大的延迟开销是不能接受的,jigsaw新版本打算对本地的通信直接使用内存共享替代而不是udp。
——————————————————————
为什么我们要多线程或者多进程编程?:
上面有提到,提升CPU资源的利用率,
到提升单核CPU性能已经不可能的时候,我们完全可以在
程序上入手,改变程序使得程序是多线程编程的。
假如你老板要求你从10人承载变成100人承载,
如果你是单线程程序,那么你可能做了一晚上优化,
终于让这个目标实现了。
但是老板哪天要求你100人变成1000人,
你发现你的代码已经没有可以优化的空间了,
但是如果你用的多线程实现,那么你只要往你
的机器上堆配置就行了。加多少配置,多载多少人,
多美妙啊!
但是。。如果老板要求你承载1000000人呢?
你打开机箱发现,你的机器的所有内存插槽都满了,
CPU也是双路、超多的线程了。
这时候,走集群!也就是俗称的负载均衡,然后调度的原理
和进程通信几乎没差,只要你程序设计的时候预留了。
然后你只要跟老板说,加机器就完事了!
————————————————————
理论上足够好的程序设计,在资源足够的情况下,能承受无穷的压力
____________________________
之后我会继续介绍操作系统底层相关的原理。
总结:java的话,程序不多线程设计,照样要遇到单线程性能瓶颈
java优势只有开发容易度 底层后端可以考虑拿go写 天生支持多线程利用所有cpu核心
原文:https://user.qzone.qq.com/854185073/blog/1568620522
好文好文
页:
[1]