goroutines大致相当于python的asyncio
任务,还有一个额外的功能,即任何CPU绑定的任务都被路由到ThreadPoolExecutor
而不是被添加到事件循环中(当然,假设我们使用没有GIL的python解释器?
我失踪的两种方法之间是否存在实质性差异?当然,除了并发性是Go的一个组成部分所带来的效率和代码清晰度之外。
答案 0 :(得分:6)
我想我知道答案的一部分。我试图总结一下我对asyncio
任务和goroutines之间差异的理解:
1)与asyncio
不同,人们很少需要担心他们的goroutine会长时间阻挡。 OTOH,跨goroutine的内存共享类似于跨线程而不是asyncio
任务的内存共享,因为goroutine执行顺序保证要弱得多(即使硬件只有一个内核)。
asyncio
只会在显式await
,yield
和某些事件循环方法上切换上下文,而Go运行时可能会打开更微妙的触发器(例如某些函数调用)。所以asyncio
是完全合作的,而goroutines主要是合作的(路线图表明它们随着时间的推移会变得更不合作)。
一个非常紧凑的循环(例如使用数值计算)仍然可以阻止Go运行时(嗯,它正在运行的线程)。如果它发生了,它将比在python中产生更小的影响 - 除非它发生在多个线程中。
2)Goroutines对并行计算有现成的支持,这需要在asyncio
下采用更复杂的方法。
Go运行时可以并行运行线程(如果有多个核可用),所以它有点类似于在无GIL的python运行时下的线程池中运行多个asyncio
事件循环,具有语言感知功能负载平衡器在前面。
3)Go运行时将自动处理单独线程中的阻塞系统调用;这需要在asyncio
下明确完成(例如,使用run_in_executor
)。
也就是说,就内存成本而言,goroutine非常类似于asyncio
任务而不是线程。
答案 1 :(得分:1)
我想你可以认为它在这下面工作,当然。它不是很准确,但足够接近。
但是有一个很大的区别:在Go中你可以编写直线代码,并且所有的I / O阻塞都会自动为你处理。您可以用简单的直线代码调用Read,然后Write,然后调用Read。使用Python asyncio,据我所知,你需要排队一个函数来处理读取,而不是只调用Read。