Golang goroutine(相对)与 C# 任务相同吗?

Tes*_*act 8 c# concurrency performance go

我一直听说 Go 是自切片面包以来最伟大的事物,但到目前为止我还没有看到太多证据证明这一点。事实上,除了等待组和同步通道之外,我还没有找到任何好的同步结构。

据说 goroutine 应该非常轻量且快速,因为它们不是实际的线程,而是 Go 使用的抽象,这让我想到了 C# 的任务。

有谁知道,根据数据或正在运行的测试,而不仅仅是口碑,goroutines 是否比 C# 任务更快/更轻?

如果我已经了解 C#,我会尝试找出使用 Go 是否有任何理由或好处。

Die*_*Epp 10

Go goroutine 和 C# 任务的行为之间存在显着差异,我不认为它们是等同的。

共同特征

它们都是能够执行 M:N 线程(少量操作系统线程之上的大量轻量级线程)的用户空间线程系统。

差异

  • Goroutines 可以被抢占。这意味着无论您有多少个受计算限制的 goroutine,您都无法阻止其他工作的进行。

  • Goroutines 可以跨 I/O 持有锁。这在 C# 任务中是不允许的。

  • 您可以使用自己选择的调度程序来控制 C# 任务的调度方式,自由地将不同的任务分配给不同的线程池,或者为任务分配优先级。您甚至可以在单个线程上运行所有 C# 任务。

  • 在 goroutine 中运行的代码只是普通的 Go 代码。必须重写 C# 代码才能使用 async/await/Task。

在我看来,C# 任务是语法糖,用于将代码重写为状态机,并将状态捕获为堆上而不是堆栈上的对象。所有调度都是在现有线程原语之上的普通库代码中完成的。

Goroutine 的设计在行为(锁、IO 和抢占)方面更接近操作系统线程,尽管它们并不完美。

如果您使用普通线程原语来等待某个条件,但任务调度程序没有剩余线程可用于调度您正在等待的任务,则很容易使 C# 任务陷入死锁。这就是为什么在持有锁时不能等待,调度程序可能会安排第二个任务,该任务最终会等待第一个任务持有的锁。

C# 处理方式的一大好处是您可以使用自己的调度程序。我在单元测试时广泛使用了这个。与 C# 中的简单测试相比,为并发 Go 代码编写测试可能有点烦人。

  • @RobertHarvey:我不认为问题的这一部分是可以回答的,所以我没有回答它。 (2认同)