理解JS与多线程
什么是四核四线程?
一个CPU有几个核它就可以跑多少个线程,四核四线程就说明这个CPU同一时间最多能够运行四个线程,四核八线程是使用了超线程技术,使得单个核像有两个核一样,速度比四核四线程有多提升。
由于四核四线程的CPU同一时间只能运行四个线程,所以有些线程会处于运行状态,而大部分的线程会处于中断、堵塞、睡眠的状态,所以这里就涉及操作系统的任务调度。
OS的任务调度
-
Linux进程分类
1)交互式进程:需要有大量的交互(如vi编译器,大部分时间处于休眠状态,但是要求响应要快。)
2)批处理进程:运行在后台(如编译程序,需要占用大量的系统资源,可以慢点。)
3)实时进程:需要立即响应并执行(如视频播放器软件,它的优先级最高。)
-
任务调度方式
常用的有以下两种:
1)SCHED_FIFO:实时进程,它的优先级最高,直到执行完了,才执行下一个实时进程。
2)SCHED_RR:对于普通线程使用时间片轮询,每个线程分配一个时间片,当前线程用完这个时间片,没有执行完的就排到当前优先级一样的线程队列队尾。
HTML5引入了Web Workers,让JS支持线程。
JS的多线程是OS级别的
JS的多线程是真的多线程,也就是说JS的多线程是调用系统API创建的多线程。
还有一种多线程是用户级别的多线程,这种多线程并不会产生实际的系统线程,它是应用程序自己控制任务切换的。
一般操作系统线程是有限制的,开太多,页面就挂了。
线程同步
线程同步主要是靠锁来实现的。锁可以分成三种。
-
互斥锁
一块代码被锁住了,只要执行完了才能释放这把锁,其他线程运行到这里的时候也要去申请那把锁,由于这把锁没有被释放,所以它就堵塞在那里了,只要等到锁被释放了,它才能拿到这把锁再继续加锁。
互斥锁使用太多会导致性能下降,因为线程堵塞在那里它要不断查那个锁能不能用,所以要占用CPU。
-
读写锁
如果只要有一个线程在读可以同时读,但是不允许有一个线程进行写入;同理只要有一个线程在写,另外的线程就不能读。
-
条件变量
条件变量是为了解决生产者和消费者的问题,由于互斥锁和读写锁会导致线程一直堵塞在那里占用CPU,而使用信号通知的方式可以先让堵塞的线程进入睡眠状态,等生产者生产出东西后通知消费者,唤醒它进行消费。
JS没有线程同步的概念
JS的多线程无法操作DOM,没有window对象,每个线程的数量都是独立的。主线程传给子线程的数据是通过拷贝复制,同样的子线程给主线程的数据也是通过拷贝复制,而不是共享同一块内存区域。
JS的单线程模型
function fn(){
// 需要执行20ms
}
function fn1(){
var fn3 = function(){};
setTimeout(fn3,0);
fn();
}
function fn2(){
fn();
var fn4 = function(){};
setInterval(fn4,20);
fn();
}
在主逻辑里面的fn1和fn2的调用是连在一起的,它是一个执行单元,要么还没执行,要么得一口气执行完,执行完之后,再执行setTimeout后面的。由于已经超过setInterval定的20ms,所以又马上执行setInterval的函数fn4.
Node.js的单线程模型
单线程如何处理高并发呢?
由于数据库连接就是多线程,调用操作系统的IO文件读取也是多线程,所以Node.js的异步是借助于数据库和IO多线程。
的单线程模型
单线程如何处理高并发呢?
由于数据库连接就是多线程,调用操作系统的IO文件读取也是多线程,所以Node.js的异步是借助于数据库和IO多线程。
这样的好处是不需要启动新的线程,不需要开辟新线程的空间,不需要进行线程的上下文切换。当服务应用不是计算类型的,使用Node.js可能反而会更快,同时由于是单线程的所以写代码更容易。缺点:不能够提供很耗CPU的服务,如图形渲染,复杂的算法计算等。