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

sec*_*rve 2 concurrency go node.js

Go非常适合并发,任务作为常规例程传递,并且在虚拟处理器中处理例程,每当一个例程遇到阻塞操作(数据库调用)时,go例程就会被移动到另一个虚拟处理器在另一个线程上,大部分时间都运行在另一个物理处理器上......现在,我们实现了并行性.

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

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

是的,Go会生成一个新的线程来处理阻塞的例程,但处理器密集型操作如何,它们是相同的,还是遭受Node问题?

hob*_*bbs 7

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

因此,如果你有一个单独的goroutine做一些CPU密集型的事情,它通常不会对其他goroutines的运行能力产生影响,因为有许多其他线程可用来运行它们.如果你的所有 goroutine都被计算占用,那么在其他人放弃CPU之前,其他人都无法运行.如果他们实际完成工作,这可能不一定是一个问题,因为所有的CPU都在做实际工作,但当然有时它可能处于对延迟敏感的情况.

如果这是一个问题,我会想到三个解决方案:

  1. runtime.Gosched在长时间计算期间使用以产生对处理器的控制,允许其他goroutine有机会运行.不需要做出其他改变; 它只是一种使用协作调度程序的方法.Gosched可能会立即返回,或者可能会在稍后返回.

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

  3. 同一枚硬币的翻转:将GOMAXPROCS提升到预期的并行计算任务数量之上.这可能是最糟糕的想法,并且至少会在一定程度上损害调度,但它仍然有效,并确保您有可用于处理事件的线程.