异步是关于现在和将来的时间间隙,而并行是关于能够同时发生的事情。
并行计算最常见的工具就是进程和线程。进程和线程独立运行,并可能同时运行:在不同的处理器,甚至不同的计算机上,但多个线程能够共享单个进程的内存。
与之相对的是,事件循环把自身的工作分成一个个任务并顺序执行,不允许对共享内存的并行访问和修改。通过分立线程中彼此合作的事件循环,并行和顺序执行可以共存。
线程1(X和Y是临时内存地址): foo()
线程2(X和Y是临时内存地址): bar
假设两个线程并行执行。它们在临时步骤中使用了共享的内存地址X和Y。
按照不同的步骤执行,最终结果不一样,请看下面:虽然JavaScript从不跨线程共享数据,但是这一层次的不确定性还是存在。所以JavaScript并不总是确定性的。
下面来看下完整运行吧~
由于JavaScript的单线程特性,foo()(以及bar())中的代码具有原子性。也就是说,一旦foo()开始运行,它的所有代码都会在bar()中的任意代码运行之前完成,或者相反。这称为完整运行(run-to-completion)特性。
由于foo()不会被bar()中断,bar()也不会被foo()中断,所以这个程序只有两个可能的输出,取决于这两个函数哪个先运行——如果存在多线程,且foo()和bar()中的语句可以交替运行的话,可能输出的数目将会增加不少!
块1是同步的(现在运行),而块2和块3是异步的(将来运行)
块1
块2
块3
块2和块3哪个先运行都有可能,所以这个程序有两个可能输出。
输出1
输出2
同一段代码有两个可能输出意味着JavaScript还是存在不确定性!
在JavaScript的特性中,这种函数顺序的不确定性就是通常所说的竞态条件(race condition)。
foo()和bar()相互竞争,看谁先运行。具体来说,因为无法可靠预测a和b的最终结果,所以才是竞态条件。
如果JavaScript中的某个函数由于某种原因不具有完整运行特性,那么可能的结果就会多得多
网友评论