城的灯

高性能编程术语

本篇文章,意在阐述并发,并行,分布式等高性能编程中的术语。请注意,本篇文章说将术语并没有标准定义,只是个人理解与定义。

Asynchronous vs. Synchronous

一个方法的调用者不能做任何事情,直到该方法执行完成返回结果或者抛出异常,那么该方法就是同步的。与其相反,方法的调用者能够继续处理有限步骤的逻辑,直到被告知(Callback,Future,Message)该方法执行完成,然后调用者再回头处理调用结果,那个该方法就是异步的。

同步API可以通过阻塞来实现,但这也不是必须的。一个CPU密集型的任务可能会导致阻塞行为。在一般情况下,我们最好使用异步API,因为这样可以保证系统在非CPU密集导致的阻塞时,可以执行别的任务。说到异步编程,就不得不说Actor,它天生就是异步的,Actor能够处理别的任务,直到收到任务完成的message,而不必等待方法调用的实际交付。


Concurrency vs. Parallelism

许多人理解的并发并行其实是存在偏差的,虽然它们的概念非常接近。这并不是吹毛求疵,因为概念的偏差,会导致我们对很多文档的理解出现歧义。并发指定的是两个或者多个事件可以在同一时间间隔发生,并行指的是两个或者多个事件可以在同一个时刻发生,从单核系统和多核系统角度来思考,便容易理解了。


Non-blocking vs. Blocking

当一个线程的延迟能够导致无限期的延迟别的线程,那么这就是我们所说的阻塞。一个非常好的例子便是同时只能被一个线程使用的互斥资源。假如一个线程无限期的持有一个资源(无限循环),在等待该资源的别的线程便永远不能执行。与此相反,非阻塞意味着没有线程能够无限期的阻塞别的线程。

非阻塞操作表现优于阻塞操作,随着包含阻塞操作的系统的逐渐运行,系统的质量是不能得到保障的。


Deadlock vs. Starvation vs. Live-lock

死锁是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程(或线程)。死锁与阻塞是密切相关的,因为一个进程(或线程)能够导致别的线程运行不下去,从而导致阻塞。

死锁情况,没有一个进程(或线程)能够向前推进,而饥饿是部分进程(或线程)能够继续执行,另一部分不能够执行。典型的例子就是一个低级的调度算法,高优先级任务比低优先级任务先执行。如果高优先级任务源源不断的输入进来,而服务器资源只够处理高优先级任务,那么将会没有一个低优先级的任务完成,那么低优先级的任务就会被饿死。

活锁与死锁类似,都是没有参与者能够向前推进。但不同之处就是,它不同于死锁由于等待资源而冻结,活锁可以认为是一种特殊的饥饿,活锁应该是一系列进程在轮询地等待某个不可能为真的条件为真。活锁的时候进程(或线程)是不会blocked,这会导致耗尽CPU资源。活锁分为单一实体活锁和协同导致的活锁。单一实体活锁,例如线程从队列中拿出一个任务来执行,如果任务执行失败,那么将任务重新加入队列,继续执行。假设任务总是执行失败,或者某种依赖的条件总是不满足,那么线程一直在繁忙却没有任何结果。协同活锁,例如两个人在窄路相遇,同时向一个方向避让,然后又同时向另一个方向避让,如此反复,结果谁也过不去。


Race Condition

多个线程或者进程在读写一个共享数据时结果依赖于它们执行的相对时间,这种情形叫做竞争。竞争条件发生在当多个进程或者线程在读写数据时,其最终的的结果依赖于多个进程的指令执行顺序。多个进程并发访问和操作同一数据且执行结果与访问的特定顺序有关,称为竞争条件。例如,假设两个进程P1和P2共享了变量a。在某一执行时刻,P1更新a为1,在另一时刻,P2更新a为2。因此两个任务竞争地写变量a。在这个例子中,竞争的“失败者”(最后更新的进程)决定了变量a的最终值。调试包含有竞争条件的程序是一件很头痛的事。大多数的测试运行结果都很好,但在极少数情况下会发生一些无法解释的奇怪现象。如果你的程序出现竞争条件,那么你的代码便会出现安全性问题,如果想对竞争条件有更多的了解,请点击此处