2017-05-30 107 views
0

这些例程大致相当于python的asyncio任务,还有一个额外的特性,任何CPU绑定任务都被路由到ThreadPoolExecutor而不是添加到事件循环中(当然,假设我们使用没有GIL的python解释器)?Goroutines vs asyncio任务+ CPU绑定调用的线程池

我错过了两种方法之间有什么实质性区别吗?当然,除了由于并发成为Go的一个组成部分而带来的效率和代码清晰度之外。

+1

“任何CPU绑定的任务被路由到它自己的线程”,这不是如何goroutines工作,所以我不知道该问题的那部分是怎么做的。 – JimB

+0

我认为去运行时动态改变线程的数量,以确保goroutines不会互相阻塞。由于事件循环已经可以在不阻塞的情况下处理I/O绑定的任务,但无法处理CPU绑定的任务,因此我得出结论认为,等同的处理方法是将CPU绑定的任务置于其自己的线程中。也许我应该说“路由到线程池”而不是“路由到它自己的线程”?我编辑了这个问题。 – max

回答

3

我想我知道答案的一部分。我试图总结一下我对asyncio任务和门店之间差异的了解,重要程度如下:

1)与asyncio不同,人们很少需要担心他们的goroutine会阻塞太久。 OTOH,跨goroutines的内存共享类似于跨线程的内存共享,而不是asyncio任务,因为goroutine执行顺序保证要弱得多(即使硬件只有一个内核)。

asyncio只会在明确的awaityield和某些事件循环方法上切换上下文,而Go运行时可能会切换更细微的触发器(如某些函数调用)。所以asyncio是完全合作的,而goroutines只是大多数合作(路线图表明他们将变得更不合作)。

一个非常紧密的循环(比如数值计算)仍然可以阻止Go运行时(以及它运行的线程)。如果发生这种情况,它将比python产生更少的影响 - 除非它出现在多线程中。 2)Goroutines对并行计算有现成的支持,这需要asyncio下的更复杂的方法。

Go运行时可以并行运行线程(如果有多个内核可用),所以它有点类似于在GIL-less python运行时下的线程池中运行多个asyncio事件循环,并且具有语言感知负载平衡器面前。

3)Go运行时会自动处理阻塞在一个单独的线程syscalls;这需要在asyncio下明确地完成(例如,使用run_in_executor)。

这就是说,就内存成本而言,goroutines非常像asyncio任务而不是线程。

1

我想你可以想象它在底下工作,当然。这并不准确,但足够接近。

但是有一个很大的区别:在Go中您可以编写直线代码,并自动为您处理所有I/O阻塞。您可以用简单的直线代码调用Read,然后Write和Read。使用Python asyncio,据我所知,您需要排队处理读取的函数,而不是只调用Read。

+0

Thx!我的自我答案是否有重大的误解? 是的,在python中,您需要使用异步IO库,或者如果它不可用,则需要将IO操作显式发送到线程池(这可以通过回退未来来简化, t打破异步代码风格)。一个天真的调用同步阻塞IO会挂起事件循环。 – max

+0

Go运行时确实会根据需要加入新线程。在比较goroutine和异步I/O函数时,我不太清楚该说些什么。他们真的不一样,所以当你说这两种方法是相同的时候,我会说这只是一个非常宽松的解释。 –

+0

不,在python asyncio中,你可以做一些类似'await stream_reader.read(num_bytes)'这与'file.read(num_bytes'在封锁世界里并没有太大的区别 –