Golang中runtime.Gosched的使用问题探讨

Golang中runtime.Gosched的使用问题探讨 大家好,

对于 runtime.Gosched 还不太理解。以下是 go doc 显示的内容。那么当我在 goroutine 中执行 runtime.Gosched() 时,它会将处理器让给其他 goroutine 运行,同时它自己是否仍会继续运行?有没有什么好的示例可以让我尝试?谢谢

(base) zwang-mac:cmd2 zwang$ go doc runtime.Gosched
func Gosched()
    Gosched yields the processor, allowing other goroutines to run. It does not
    suspend the current goroutine, so execution resumes automatically.

更多关于Golang中runtime.Gosched的使用问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

jameswang2015:

那么当我在goroutine中执行runtime.Gosched()时,它会把处理器让给其他goroutine运行

简单来说,并发不等于并行。在多核处理器(如i3、i5等)上,调度goroutine并不简单意味着两个核心同时运行maingoroutine进程(那是并行)。因此,maingoroutine共享同一个处理核心,以看似并行工作的方式运行(这才是并发)。

由于maingoroutine共享同一个处理核心,goroutine之间(注意:main本身也是一个goroutine)经常会发生核心切换。这就是为什么需要提供runtime.Gosched()

请注意,如果您的并发代码经过良好规划和执行(例如妥善处理通道I/O),您很少需要调用runtime.Gosched()

jameswang2015:

有没有可以尝试的好例子?谢谢

您可以尝试使用互斥锁重新实现Go中的通道功能。这可能很浪费时间,但这是我之前见过它使用的一个案例。

更多关于Golang中runtime.Gosched的使用问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,runtime.Gosched() 是一个用于主动让出处理器(P)给其他goroutine运行的函数。根据官方文档说明,调用Gosched()不会挂起当前goroutine,而是暂时让出执行机会,但当前goroutine仍处于可运行状态,之后会被调度器重新调度执行。

关键点解释:

  • 让出处理器:当前goroutine主动放弃占用的处理器时间片,允许其他就绪的goroutine运行。
  • 不挂起goroutine:当前goroutine不会进入阻塞状态,而是被放回全局运行队列,等待下次调度。
  • 自动恢复执行:调度器会在后续的某个时间点自动恢复该goroutine的执行。

示例代码:

以下示例演示了runtime.Gosched()的行为。我们创建两个goroutine,其中一个频繁调用Gosched()来让出处理器,观察它们的执行顺序变化。

package main

import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	// Goroutine 1: 频繁调用 Gosched
	go func() {
		defer wg.Done()
		for i := 0; i < 5; i++ {
			fmt.Printf("Goroutine 1: %d\n", i)
			runtime.Gosched() // 让出处理器,给其他goroutine机会
		}
	}()

	// Goroutine 2: 不调用 Gosched
	go func() {
		defer wg.Done()
		for i := 0; i < 5; i++ {
			fmt.Printf("Goroutine 2: %d\n", i)
		}
	}()

	wg.Wait()
}

运行结果分析: 多次运行此程序,输出顺序可能不同。由于Goroutine 1在每次循环中调用runtime.Gosched(),它会更频繁地让出处理器,导致Goroutine 2有更多机会执行。典型输出可能如下(顺序可能变化):

Goroutine 1: 0
Goroutine 2: 0
Goroutine 2: 1
Goroutine 1: 1
Goroutine 2: 2
Goroutine 1: 2
...

进一步测试示例:

以下示例更明确地展示了Gosched()的效果,通过一个长时间运行的goroutine来观察让出行为:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	// 设置使用1个处理器,便于观察调度行为
	runtime.GOMAXPROCS(1)

	go func() {
		for i := 0; i < 3; i++ {
			fmt.Printf("Without Gosched: %d\n", i)
		}
	}()

	go func() {
		for i := 0; i < 3; i++ {
			fmt.Printf("With Gosched: %d\n", i)
			runtime.Gosched()
		}
	}()

	// 等待goroutine执行
	time.Sleep(time.Second)
}

在这个示例中,由于设置了GOMAXPROCS(1),只有一个处理器可用。调用Gosched()的goroutine会主动让出处理器,使得另一个goroutine能够插入执行。

总结:runtime.Gosched()是一种协作式调度手段,适用于调试或特定场景下的公平性调整,但在生产代码中应谨慎使用,因为Go调度器通常能自动高效地管理goroutine执行。

回到顶部