事件驱动、多线程和Go协程,为什么不被更多地使用?

huangapple 未分类评论71阅读模式
英文:

Evented, Threaded, and Go Routines, why not used more?

问题

事件驱动和线程模型非常受欢迎,通常会被广泛讨论。

“线程”方法中,每个I/O操作都可能会阻塞,这种方法更简单。编写和调试同步代码更容易,事实上,大多数生态系统都提供了阻塞I/O库,只需使用线程池,正确配置即可。

但是...它不可扩展。

然后是“事件驱动”方法,其中有一个线程(或每个CPU一个线程),它不会阻塞并且只执行CPU指令。当I/O返回时,它会激活适当的计算,从而更好地利用CPU。

但是...编码更难,容易创建难以阅读的混乱代码,没有足够的异步I/O库等等...非阻塞和阻塞I/O不兼容。在没有从一开始就设计为非阻塞的生态系统中使用它非常有问题。在NodeJS中,所有I/O从一开始就是非阻塞的(因为JavaScript从一开始就没有I/O库)。尝试在C++/Java中实现相同的功能吧,但是一次同步调用就足以降低性能。

然后出现了Go。我最近开始研究Go,因为我发现它的并发模型很有趣。Go让你能够“兼顾两全”,所有I/O都是阻塞的,编写同步代码,但同时享受CPU的充分利用。

Go有一个称为“Go协程”的线程抽象,它们基本上是用户级线程,“Go运行时”(与您的程序一起编译)负责在真实的操作系统线程上调度不同的Go协程(假设每个CPU一个线程)。每当一个Go协程执行系统调用时,“Go运行时”会调度另一个Go协程在其中一个操作系统线程上运行,它将Go协程“多路复用”到操作系统线程上。

用户级线程并不是一个新概念,Go的方法很好,也很简单,所以我开始思考,为什么JVM世界不使用类似的抽象,相比于底层通常发生的情况,这是小菜一碟。

然后我发现它确实使用了,Sun的1.2版本的JVM称之为绿色线程,它们是用户级线程,但是它们只被多路复用到一个单一的操作系统线程中,后来它们转向了真实的操作系统线程以利用多核CPU。


**为什么在JVM世界1.2版本之后这个问题不再相关?**我是否没有看到Go方法的缺点?也许有一些适用于Go的概念,在JVM上无法实现?

英文:

The Evented and Threaded models are quite popular and are usually discussed a lot.

The 'Threaded' approach, where every I/O operation can block, is simpler. It's easier to write and debug synchronous code, and the fact of the matter is that most ecosystems provide blocking I/O libraries, just use a thread pool, configure it properly and you're good to go.

But.. it doesn't scale.

And then there's the 'Evented' approach, where there is one thread (or one per cpu) that never blocks and performs only CPU instructions. When IO returns, it activates the appropriate computation, allowing better utilization of the CPU.

But.. it's harder to code, easier to create unreadable spaghetti code, there aren't enough libraries for async I/O etc... And non-blocking and blocking I/O don't mix well. It's very problematic to use in ecosystems that weren't designed from the ground up to be non-blocking. In NodeJS all I/O is non-blocking from the beginning (because javascript never had an I/O library to begin with). Good luck trying to implement the same in C++/Java. You can try your best, but it would take one synchronous call to kill your performance.

And then came Go. I started looking into Go recently because i found it's concurrency model interesting. Go gives you the ability to "get the best out of both worlds", all I/O is blocking, write synchronous code, but enjoy the full utilization of the CPU.

Go has an abstraction to Threads called 'Go Routines', which are basically user level threads, the 'Go Runtime' (which gets compiled in with your program) is in charge of scheduling the different Go Routines on real OS threads (let's say 1 per CPU) whenever a Go Routine performs a system call the 'Go Runtime' schedules another Go Routine to run in one of the OS threads, it 'multiplexes' the go-routines onto the OS threads.

User level threads isn't a new concept, Go's approach is nice, and simple, so I started wondering, why doesn't the JVM world use a similar abstraction, it's child's play compared to what usually happens there under the hood.

Then I found out it did, Sun's 1.2 JVM called them green threads which were user level threads, but the were only multiplexed into a single OS thread, they moved on to real OS threads to allow utilizing multi-core CPU's.


Why wasn't this relevant in the JVM world after 1.2? Am I failing to see the downsides of the Go approach? Maybe some concept that applies to Go, but would not be implementable on the JVM?

huangapple
  • 本文由 发表于 2013年6月25日 23:05:27
  • 转载请务必保留本文链接:https://java.coder-hub.com/17300941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定