multithreading - Goroutines 是协作调度的。这是否意味着不让出执行的 goroutine 会导致 goroutine 一个一个运行?

标签 multithreading go scheduling goroutine

发件人:http://blog.nindalf.com/how-goroutines-work/

As the goroutines are scheduled cooperatively, a goroutine that loops continuously can starve other goroutines on the same thread.

Goroutines are cheap and do not cause the thread on which they are multiplexed to block if they are blocked on

  • network input
  • sleeping
  • channel operations or
  • blocking on primitives in the sync package.

鉴于上述情况,假设您有一些这样的代码,除了循环随机次数并打印总和之外什么都不做:

func sum(x int) {
  sum := 0
  for i := 0; i < x; i++ {
    sum += i
  }
  fmt.Println(sum)
}

如果你像这样使用goroutines

go sum(100)
go sum(200)
go sum(300)
go sum(400)

如果你只有一个线程,goroutines会一个一个运行吗?

最佳答案

所有 creker 评论的汇编和整理。

抢占意味着内核(运行时)允许线程运行一段特定的时间,然后在其他线程不做任何事情或不知道任何事情的情况下将执行权交给其他线程。在通常使用硬件中断实现的操作系统内核中。进程不能阻止整个操作系统。在协作式多任务线程中,线程必须显式地将执行权让给其他线程。如果不这样做,它可能会阻止整个过程甚至整个机器。 Go 就是这样做的。它有一些非常具体的点,goroutine 可以让出执行。但是,如果 goroutine 只是为 {} 执行,那么它将锁定整个进程。

但是,引用中没有提到运行时的最新变化。 fmt.Println(sum) 可能会导致其他 goroutine 被调度,因为较新的运行时将在函数调用时调用调度程序。

如果您没有任何函数调用,只是一些数学运算,那么是的,goroutine 将锁定线程,直到它退出或遇到可能让其他人执行的事情。这就是 for {} 在 Go 中不起作用的原因。更糟糕的是,由于 GC 的工作原理,即使 GOMAXPROCS > 1,它仍然会导致进程挂起,但无论如何你不应该依赖它。了解这些东西很好,但不要指望它。甚至有人提议在像您这样的循环中插入调度程序调用

Go 的运行时所做的主要事情是它尽最大努力让每个人都能执行并且不会饿死任何人。它是如何做到的,语言规范中没有具体说明,将来可能会改变。如果关于循环的提议得到实现,那么即使没有函数调用切换也可能发生。目前,您唯一应该记住的是,在某些情况下,函数调用可能会导致 goroutine 放弃执行。

为了解释 Akavall 的答案中的切换,当 fmt.Printf 被调用时,它做的第一件事是检查它是否需要增加堆栈并调用调度程序。它可能会切换到另一个 goroutine。它是否会切换取决于其他 goroutine 的状态和调度程序的具体实现。像任何调度程序一样,它可能会检查是否有应该执行的饥饿 goroutines。通过多次迭代,函数调用有更大的机会进行切换,因为其他人的饥饿时间更长。在饥饿发生之前,goroutine 完成几次迭代。

关于multithreading - Goroutines 是协作调度的。这是否意味着不让出执行的 goroutine 会导致 goroutine 一个一个运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37469995/

相关文章:

java - 有时在计划任务中没有任何内容打印到 servlet 的输出流

linux - 选择 Linux I/O 调度程序

linux - Linux 内核线程的调度或抢占是如何工作的?

java - 核心java多线程-线程没有结束

c++ - 为什么taskset对fedora没有影响?

C# 套接字 : synchronous calls within asynchronous ones

go - 如何知道我们可以使用 go 包的功能?

http - Golang net/http2请求返回nil

python - 等待线程完成使用连接。很基本

Go:在 '|'字符前加反斜杠