在Go语言中,我们可以使用channel和sync.Mutex等工具来确保一组goroutine按照预定顺序执行。下面是一个简单的示例,展示如何通过channel传递令牌(token)来实现这一目标:
package main
import (
"fmt"
"sync"
)
// 定义一个全局唯一的令牌通道
var tokenChan = make(chan struct{}, 1)
// 定义一个全局的互斥锁
var mutex = &sync.Mutex{}
// 任务接口,每个任务都需要实现这个接口
type Task interface {
Execute(order int)
}
// 一个具体的任务结构体示例
type ExampleTask struct{}
func (et ExampleTask) Execute(order int) {
mutex.Lock()
fmt.Printf("Task executing with order %d\n", order)
// 模拟任务执行
// ...
mutex.Unlock()
// 任务执行完毕后,向通道放回令牌,允许下一个任务执行
tokenChan <- struct{}{}
}
func main() {
// 初始化任务列表
tasks := []Task{
ExampleTask{},
ExampleTask{},
ExampleTask{},
// 更多任务...
}
// 把第一个令牌放入通道
tokenChan <- struct{}{}
// 启动goroutine来顺序执行任务
for index, task := range tasks {
go func(index int, task Task) {
// 从通道获取令牌,这意味着当前goroutine可以开始执行任务
<-tokenChan
// 执行任务
task.Execute(index + 1) // 注意,此处索引+1是因为人类习惯于从1开始计数
// 任务执行结束后,解锁下一个goroutine
}(index, task)
}
// 确保main函数不会提前结束,等待所有任务完成
// 在实际场景中,你可能需要使用sync.WaitGroup或者其他机制来同步
// 这里为了简化示例,假设main函数会一直运行直到所有任务结束
select {}
}
在这个示例中,我们创建了一个只包含一个元素的channel(令牌通道)和一个互斥锁。每个goroutine必须先从令牌通道中获取令牌才能开始执行任务,执行完后将令牌放回通道。这种机制确保了只有拿到令牌的goroutine才能执行任务,从而达到顺序执行的目的。注意,实际场景中可能需要采用不同的同步机制来确保main函数不会提前结束,这里仅做示意,没有加入完整的退出逻辑。