drztpx8735
2018-07-17 07:45
浏览 76
已采纳

Nodejs EventLoop(带有集群模块)和Golang Scheduler的比较

In nodejs the main critics are based on its single threaded event loop model.

The biggest disadvantage of nodejs is that one can not perform CPU intensive tasks in the application. For demonstration purpose, lets take the example of a while loop (which is perhaps analogous to a db function returning hundred thousand of records and then processing those records in nodejs.)

while(1){
    x++
}

Such sort of the code will block the main stack and consequently all other tasks waiting in the Event Queue will never get the chance to be executed. (and in a web Applications, new users will not be able to connect to the App).

However, one could possibly use module like cluster to leverage the multi core system and partially solve the above issue. The Cluster module allows one to create a small network of separate processes which can share server ports, which gives the Node.js application access to the full power of the server. (However, one of the biggest disadvantage of using Cluster is that the state cannot be maintained in the application code). But again there is a high possibility that we would end up in the same situation (as described above) again if there is too much server load.

When I started learning the Go language and had a look at its architecture and goroutines, I thought it would possibly solve the problem that arises due to the single threaded event loop model of nodejs. And that it would probably avoid the above scenario of CPU intensive tasks, until I came across this interesting code, which blocks all of the GO application and nothing happens, much like a while loop in nodejs.

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0)
    for i := 0; i < threads; i++ {
        go func() {
            for { x++ }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}
//or perhaps even if we use some number that is just greater than the threads.

So, the question is, if I have an application which is load intensive and there would be lot of CPU intensive tasks as well, I could probably get stuck in the above sort of scenario. (where db returns numerous amount of rows and then the application need to process and modify some thing in those rows). Would not the incoming users would be blocked and so would all other tasks as well?

So, how could the above problem be solved?

P.S
Or perhaps, the use cases I have mentioned does not make much of the sense? :)

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doulu3865 2018-07-17 09:16
    已采纳

    Currently (Go 1.11 and earlier versions) your so-called tight loop will indeed clog the code. This would happen simply because currently the Go compiler inserts code which does "preemption checks" («should I yield to the scheduler so it runs another goroutine?») only in prologues of the functions it compiles (almost, but let's not digress). If your loop does not call any function, no preemption checks will be made.

    The Go developers are well aware of this and are working on eventually alleviating this issue.

    Still, note that your alleged problem is a non-issue in most real-world scenarious: the code which performs long runs of CPU-intensive work without calling any function is rare and far in between.

    In the cases, where you really have such code and you have detected it really makes other goroutines starve (let me underline: you have detected that through profiling—as opposed to just conjuring up "it must be slow"), you may apply several techniques to deal with this:

    • Insert calls to runtime.Gosched() in certain key points of your long-running CPU-intensive code. This will forcibly relinquish control to another goroutine while not actually suspending the caller goroutine (so it will run as soon as it will have been scheduled again).
    • Dedicate OS threads for the goroutines running those CPU hogs:
      1. Bound the set of such CPU hogs to, say, N "worker goroutines";
      2. Put a dispatcher in front of them (this is called "fan-out");
      3. Make sure that N is sensibly smaller than runtime.GOMAXPROCS or raise the latter so that you have those N extra threads.
      4. Shovel units of work to those dedicated goroutines via the dispatcher.
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题