Go会阻止像Node这样的处理器密集型操作吗?

Go对于并发是很好的,任务作为例行程序传递,并且例行程序在虚拟处理器中处理,每当一个例行程序遇到阻塞操作(数据库调用)时,将例行程序移动到另一个虚拟处理器在不同的线程上,这是大多数时间在另一个物理处理器上运行的…现在,我们实现了并行性。

Node.js有一个类似的技术(除了一切发生在同一个线程上),但是把所有正在等待的虚拟进程放在一个等待队列中,直到它们从阻塞资源(DB,URL)接收到响应,然后发送它们进行处理。

Node.js的缺点是无法处理处理器密集型操作(for循环就是一个例子),而虚拟进程正在运行,所有的时间都将耗尽,直到完成而没有抢占,这就是为什么Node.js是明智的在用于关键系统之前,尽pipe它具有很高的并发可用性。

是的,Go产生了一个新的线程来处理阻塞执行程序,但是处理器密集型操作又是如何被认为是相同的,还是会受到Node问题的困扰?

是的,但在实践中遇到的困难要比使用Node更容易,并且从中恢复起来要容易得多。 节点是单线程的,除非你写明确的多进程代码(这并不总是很容易,尤其是如果你想要可移植的话)。 Go使用N:M调度,并且具有一定的最大运行线程数(等于默认情况下的逻辑CPU数,但是可调)。 注意正在运行 :正在等待阻塞操作的goroutine被“冻结”,并不会占用正在运行的线程。

因此,如果你有一个单独的goroutine做一些CPU密集型的工作,它通常不会影响到其他goroutine的运行能力,因为有很多其他的线程可以运行它们。 如果你所有的例程都被计算所占用,那么其他的程序在CPU放弃之前是不会有机会运行的。 如果他们实际上正在完成工作,这可能不一定是个问题,因为所有的CPU都在做实际的工作,但是当然有时候可能会出现在延迟敏感的情况下。

如果这是一个问题,三个解决scheme就会浮现出来:

  1. 使用runtime.Gosched在长时间的计算中产生处理器的控制权,让其他goroutines有机会运行。 没有其他的改变必须做。 这只是与合作调度程序一起工作的一种方式。 Gosched可能会立即返回,也可能稍后返回。

  2. 使用工作池将并行CPU密集型工作量限制为小于GOMAXPROCS。 Go使这很容易。

  3. 同一个硬币的Flipside:提高GOMAXPROCS的预期数量的并行计算任务。 这可能是最糟糕的想法,并会至less有些伤害调度,但它仍然会工作,并确保您有线程可用于处理事件。

Go使用合作多任务 。 一个没有做任何放弃对Go调度程序控制的程序,可以垄断一个线程。