请教 java的多线程 与 node.js的多事件 应该如何理解
发布于 6 年前 作者 maosiyu 4086 次浏览 来自 问答

问题引发是 java的多线程 与 node.js的多事件 区别 应该如何理解

线程 和 事件 是什么关系? 事件 是什么? 多线程 和 多事件 的区别是什么? cpu 如何处理多线程? cpu 如何处理单线程多事件?

如偶遇大神还请 从 进程 线程 事件的由来的角度 讲解一下 不胜感激!

12 回复

留坑,周末整理一波看看我能不能说清楚🤣

@cctv1005s 先重重的感谢一下, 我学到这块儿有一点自己的理解, 就是所有的语法糖 都是对 硬件cpu多核 带来的问题, 作出了自己的一套解决方案,比如java的多线程的类 jvm对这些问题的控制; 相对 node.js 也有他自己的解决方案多事件; 不知道我理解的对不对。 期待大神的指点!

线程会创建一个执行环境,但是会共享进程内的资源,线程由于共享资源内存,所以不存在通信问题。 进程间相互独立,跟独立的 app 一样,通过类似于 rpc 的方式通信,很多种,信号量,内存之类的。这涉及到并发编程。

事件就是一个 while 不停的检测队列里面是否有函数需要执行。这就是异步编程,函数式编程 csp。

cpu 跟核心数有关吧,一个核心就像一个单独的个体,能做一件事,所以在相同参数下,为啥cpu 核越多越牛逼。 单个 cpu 一次还是只能做一件事,只是切换有些快,对你来说,你感觉不到。

浅显理解,这方面还是了解的少,用的少,看了忘。

@MiYogurt 感谢你的回答, 事件就是一个 while 不停的检测队列里面是否有函数需要执行。 这一句我还是不理解, 我能理解 一个进程内部为了实现并发而创造了线程,那么是不是可以也可以理解为 一个线程内为了实现并发,人类又创造了事件? 如果是那么java 为什么没这么做? 如果我想错了,那到底应该 怎么理解呢,最好是在通俗一点儿,大白话也好。感谢

@maosiyu 一个线程内为了实现并发,人类又创造了事件?各个事件之间不是因该也是同步执行的么?个人理解为事件有一个注册跟触发的过程,无论是注册还是触发的过程应该都是同步执行的吧。 个人感觉,事件只不过是把触发条件跟函数两者结合起来了,在特定的时间执行函数,跟并发没有任何联系。至于并发,java是通过多线程,node通过cluster开启多个进程来更好的利用cpu。 (个人感觉,有问题欢迎指出)

@MiYogurt 一个核心同时只能处理一件事不太对,比如英特尔大多处理器支持超线程,可以同时让两个线程用一个核的不同部分。

(不严格地)一个进程包含数个线程,线程间共享资源,操作系统会以线程为单位,把它们平衡到不同cpu核心上。node也可以用多线程来充分利用cpu的,不一定是多进程。 应该要理解成,事件这个概念,是上升到JS引擎才出现的,更底层不存在JS的所谓事件。 一般JS引擎会依照规范,建立事件循环。 以node和V8为例,node建立一个进程,包含多个线程,其中一个跑着你的JS代码,其他负责编译优化,IO等。 然后跑着js的线程中,主要有一个循环,有主要的两个事件队列,一个叫marco,一个叫micro,这个循环就是始终执行这两个队列,直到清空。 比如setTimeout就是在给定时间之后,将事件放入marco队列,Promise.resolve().then是将事件放入micro队列,而你的总的js代码,是放入marco队列,第一个执行的。更多请谷歌。

@xyzingh 是有多线程,不过我说的进程。没有再细分。

vvvv我饿

来自酷炫的 CNodeMD

@William17 对,事件循环的规范不在es里,是在HTML的规范(https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)。 上面有人分享的宏任务微任务执行顺序之类的,这是主流浏览器的行为,node是有差异的,但是这个差异将在node v11版本被消除,node v11还提供了新实验性 queueMicrotask api,去了解下比较好。

线程属于进程内,共享内一套内存,线程间不需要通讯,但需要可以控制,比如唤醒,锁,休眠等等,为什么还是需要控制?因为处理器在同一瞬间只能做一个运算,线程间会去争抢这个机会,主要是线程可以共享进程资源,Java可以创建多线程解决阻塞问题。node是单线程的,这就代表一个进程 比如node index.js,就只能有一个线程,node通过异步回调(更深层不太清楚要怎么解释),实现代码不阻塞,线程会不断进行计算,因为有很多“任务”在等待,这样就实现了通过一个线程运行“看起来能够并发”的工作,并且效率会非常高,多进程的node是为了更充分使用多核的优势,但是,这种情况下就需要考虑进程间如何通讯,因为一个应用中比如定时任务,消息队列,全局变量会因为简单的开启多进程而产生冲突,因为,他们不共享内存。个人觉得事件并不和进程和线程是相同类型的概念,另外其实没有真正的异步,最底层都是同步的,这时因为真的计算机就只能同时运行一个计算,只是通过什么方式去select可读,会看起来比较异步,以上都是个人瞎bb。

@HobaiRiku 你可能说的是JS方向的底层,如果是汇编和机器指令方向的底层怕是没有任何语言能实现多真异步了。 但对于一门语言来说nodejs的底层就是真异步。举个例子,比如实现curl功能,传统来说就是等待请求返回的时候是CPU不断的判断是否请求返回。而nodejs来说既然请求始终是要一定的时间,那我就把你放到队列里面,等会再判断是否返回。 那么等待返回的时间里,传统做法是让CPU就不断地死循环判断是否请求返回(这时就阻塞了,浪费大量没必要的CPU资源),而nodejs就在这个等待过程做完其它事情再判断,这就极大解放了CPU使用率。 解放了CPU但为什么node的瓶颈又是CPU呢,其实原因也很简单,就是node在设计之初就对异步写法是使用难度上进行了极大的折中,使得异步非常简单就能实现。 所以过于傻瓜化的异步实现,必然会有傻瓜的CPU瓶颈。我相信在后续只要nodejs多线程设计者不SB,很容易就可以实现类似协程(像带锁功能估计悬)相结合,既能使用简单,但又性能不差的nodejs。


另外对作者的解答,JAVA的多线程一般来说也是使用传统方法进行,而多线程在CPU的实现是通过CPU中断来实现,即是根据优先级中断一个的运行来运行另一个。而多核CPU,假设为4核。那么最多并行4个,如果开了1000个线程,意味着要中断1000次才能有效执行4次。中断还往往要切换调用栈的上下文,这都是多余无用的运算。为什么JAVA没有那样做,这样在那个时候普遍被认为实现难度过高,且那个时候这种思想并未深入人心。

来自酷炫的 CNodeMD

回到顶部