设为首页收藏本站

ZMX - IT技术交流论坛 - 无限Perfect,追求梦想 - itzmx.com

 找回密码
 注册论坛

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

用百度帐号登录

只需两步,快速登录

搜索
查看: 1904|回复: 1

转:[线程原理]为什么脚本语言大多数是单线程的?汇编语言,C java python go CPU多核心利用率解析

[复制链接]
 成长值: 18

签到天数: 4467 天

[LV.Master]伴坛终老

发表于 2019/9/17 20:54 | 显示全部楼层 |阅读模式 |Google Chrome 76.0.3809.132|Windows 10
天涯海角搜一下: 百度 谷歌 360 搜狗 有道 雅虎 必应 即刻
最近终于搞懂了线程的概念,

①任何一个CPU的单位时间内,只能做一件事,一般是指令集内的一个指令(参考汇编指令集)
②性能越强的CPU,单位时间可以做的越短

于是,在任何一秒内,CPU可以被抽象成这样
1.png
如果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有四个线程,强制利用上不行吗:

强制利用上会是这样的:

2.png

所以无论怎样,只要有这个限制在,CPU永远只能利用25%。


————————————————
提升CPU单核性能,即可以让上述表格更加密集,但成本是昂贵的。
于是大多数大型项目,都会使用多线程编程。
例如java(自带封装好的Thread类),C(可以使用winapi的CreateThread)

那么像node、python(也是单线程语言平台),就没有解决办法了吗?
答案是,有。


只要你能处理好资源的调用,即同一时间"一定"不能发生两次的对同一资源的使用,那么你可以安全的使用线程来
加速计算。或者说,对CPU资源的利用率。

但是在脚本语言中,并不存在创建线程的接口(实际上,你仍然有办法调用系统API强制创建线程,这里暂不讨论,我们应当利用语言本身自带的东西实现)

大多数脚本语言都会有一个内置(built-in)的模块,子进程!
(python中是multiprocessing,node.js中是child_process)

可以这样理解:

3.png
黄色代表进程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

欢迎光临IT技术交流论坛:http://bbs.itzmx.com/
回复

使用道具 举报

签到天数: 6 天

[LV.2]偶尔看看I

发表于 2019/10/6 13:15 来自手机 | 显示全部楼层
好文好文
欢迎光临IT技术交流论坛:http://bbs.itzmx.com/
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册论坛 新浪微博账号登陆用百度帐号登录

本版积分规则

手机版|Archiver|Mail me|网站地图|IT技术交流论坛 ( 闽ICP备13013206号-7 )

GMT+8, 2024/3/28 23:13 , Processed in 0.165770 second(s), 22 queries , MemCache On.

Powered by itzmx! X3.4

© 2011- sakura

快速回复 返回顶部 返回列表