Code is like life. 代码 ≈ 生活
函数除了拿来调用外,还可以创建新的类型:
function People(name) { this.name = name; this.getName = function() { return this.name; } } var p = new People("Jack"); console.log(p instanceof People); // => true console.log(p.getName()); // => "Jack"
那么,这个对象里都有什么呢?我们可以把它打印出来看看:
可以看到,除了我们放进去的name、getName,还有一个__proto__
。它是什么,我先卖个关子。我们先看看“instanceof”,和其他语言类似:
var p = new People("Jack"); console.log(p instanceof People); // => true console.log(p instanceof Object); // => true
我们可以笼统地认为,People继承于Object。不过,JS中的instanceof其实没有那么简单,MDN上是这样写的:The instanceof operator tests whether the prototype prototype of a constructor appears anywhere in the prototype chain of an object.
接下来我们先看看prototype是什么,将上面的People打印一下:
它其实就是一个普普通通的对象,那么,它和new出来的对象有什么关系?可以用这张图表示:
这张图是什么意思呢?在内存中,prototype和它实例化出的__proto__
是同一个对象。这有什么意义?我们知道,JavaScript中会这样寻找属性、方法:
__proto__
上寻找__proto__
的__proto__
上寻找……所以,我们可以这样写:
function People(name) { this.name = name; } People.prototype.getName = function() { return this.name; } var p = new People("Jack"); console.log(p.getName()); var p2 = new People("Jason"); console.log(p2.getName());
再举个例子,我们从文档中可以查到hasOwnprototype的方法,MDN上有这样的描述:
所有继承了 Object 的对象都会继承到 hasOwnprototype 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;
如果我们运行p.hasOwnprototype("name")
,JavaScript怎么找到hasOwnprototype的呢?它会:
__proto__
,也就是People.prototype
上寻找——没找到__proto__
上寻找。因为People.prototype是一个对象,直接父类是Object,所以,也就是Object.prototype
上寻找操作系统是多久诞生的?从定义上来说,最早的时候,人们是通过各种按钮控制计算机的,这时候还没有操作系统。不过,如果我们认为,只要是让人们操作计算机的工具,都可以称为操作系统的话,说计算机从诞生之日起便有操作系统,这种话其实基本上也是正确的。操作系统的功能、原理是一直在发展的。几十年前的操作系统,和几十年后的,虽然它们都被称为操作系统,但是可能已经是两个东西了。
最早的计算机编程是通过纸带进行的。“程序员”将记载着程序的纸带放进计算机,计算机执行完毕后把结果纸带“吐”出来,这便是最早的人机交互。最早的时候计算机是独占的,你需要使用的话,就必须等前一个人用完。为了提高资源使用率,陆陆续续出现了批处理操作系统、分时操作系统和实时操作系统。分时操作系统在一定程度上已经接近于今天的操作系统了。它使用时间片的方式轮流分配CPU资源,用来处理多个用户的作业。
今天的操作系统,最基础的其实也是时间片,但是在它的基础上进行了很多改进。
计算机逐渐发展,操作系统逐渐变得复杂。操作系统有一大功能叫“资源管理”,它怎么给程序分配资源呢?于是,进程的概念也被提出来了。进程是进行资源分配和调度的基本单位。我们仅从最简单的理论上来说,进程包括两个部分,一个是Process Control Block(PCB,程序控制块)和程序块。PCB是系统用来控制一个进程的“工具”,也是进程存在的标志。PCB中包含了进程的一些基本信息,例如,进程的ID,程序运行的堆栈,程序的运行数据等。而程序块则是进程真正执行的代码。
操作系统一般通过时间片算法来管理一个进程。它把CPU分成很多个很小的“片段”,并把它们轮流分配给进程使用。当时间片耗尽后,进程就会被系统“暂停”,将它的数据放入PCB,然后进程就进入了“就绪”队列。因此,从微观角度来讲,单个CPU某一时刻只能执行一个进程。
当进程需要其他外部资源时会怎样呢?例如一个进程需要读写文件,如果缓冲区没有它需要的数据,那么就意味着内核需要去外部储存读取。外部储存的读写对计算机来说是很慢的,CPU资源不应该被白白浪费,于是,内核就会让进程进入阻塞状态。当进程需要的资源准备好的时候,进程就可以继续了吗?答案是否定的,它需要重新“排队”,才能继续运行。
线程的提出,是因为人们觉得进程切换开销太大,因此想要一个更“轻”的进程。线程提出之初,其实用处并不大,直到出现了多核心处理器。
前面提到了,进程是进行资源分配和调度的基本单位,那么,我们现在可以说,线程是进行资源调度的最小单位。与进程类似,线程也有一个叫做“Thread Control Block”的存在(TCB,线程控制块)。不过,这里需要注意,因为线程拥有的系统数据非常少,因此我们基本上忽略不计。所以说,线程并不能拥有资源,它只能使用进程的资源。线程比起进程更加轻量、灵活。进程的切换涉及到系统资源,而线程则不然。
因为以上特点,我们可以看出:
在开始介绍线程的时候,我们说到了“多核处理器”。那么,为什么多核处理器能够让线程的能力得以体现?我们先说一下基本概念:处理器(CPU)=运算器+寄存器+控制器。其中,运算器就是我们所说的“核”。多个核心共享寄存器。和进程、线程类比一下是不是很相似?进程独占资源,线程则共享资源。因此,每有一个核心,就可以有一个线程在它上面运行。
Intel前几年有一项新技术叫做“超线程”,它大概意思就是,把一个核心“伪装”成多个核心,达到同时运行多个线程的目的。众所周知,线程在运行的时候总还是会有一些浪费资源的情况,因此,“超线程”对于多线程任务会有比较明显的提升,但是对于单线程任务可能反而会有一些下降。
Copyright © 2016 - 2019 泷涯生活. 蜀ICP备14012003号-2