You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Goroutine内部实现暂停与恢复处理?

实现Go控制台程序的暂停/恢复功能

要实现pause和resume命令,核心是通过通道传递不同的控制指令,并在goroutine内部维护运行状态。以下是改造后的完整代码,以及关键逻辑说明:

改造后的完整代码

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"time"
)

// 定义控制命令类型,统一管理所有控制指令
type Command string

const (
	CmdPause  Command = "pause"
	CmdResume Command = "resume"
	CmdStop   Command = "stop"
)

func main() {
	fmt.Println("starting...")
	reader := bufio.NewReader(os.Stdin)

	// 用一个通道传递所有控制命令,替代原有的quit通道
	cmdChan := make(chan Command)
	last := 1
	isRunning := false // 标记计数器是否正在运行,避免重复启动

	for {
		text, _ := reader.ReadString('\n')
		text = strings.TrimSpace(text)
		fmt.Printf("entered: %s\n", text)

		switch text {
		case "start":
			if !isRunning {
				fmt.Println("starting")
				isRunning = true
				go counter(last, 1, cmdChan, &last, &isRunning)
			} else {
				fmt.Println("counter is already running")
			}
		case "pause":
			if isRunning {
				fmt.Println("pausing")
				cmdChan <- CmdPause
			} else {
				fmt.Println("counter is not running")
			}
		case "resume":
			if isRunning {
				fmt.Println("resuming")
				cmdChan <- CmdResume
			} else {
				fmt.Println("counter is not running")
			}
		case "stop":
			if isRunning {
				fmt.Println("stopping")
				cmdChan <- CmdStop
			}
		}

		fmt.Printf("last is %v\n", last)
	}
}

func counter(startFrom int, multiplyBy int, cmdChan <-chan Command, last *int, isRunning *bool) {
	defer func() { *isRunning = false }() // goroutine退出时标记为未运行
	paused := false
	x := startFrom

	for x < 100 {
		if !paused {
			time.Sleep(time.Millisecond * 1000)
			result := x * multiplyBy
			*last = result
			fmt.Printf("%d\n", result)
			x++
		}

		// 监听控制命令,处理暂停/恢复/停止
		select {
		case cmd := <-cmdChan:
			switch cmd {
			case CmdPause:
				paused = true
				fmt.Println("counter paused")
			case CmdResume:
				paused = false
				fmt.Println("counter resumed")
			case CmdStop:
				fmt.Println("counter stopped")
				return
			}
		default:
			// 如果没有命令且未暂停,继续循环;如果已暂停,阻塞等待命令
			if paused {
				cmd := <-cmdChan
				switch cmd {
				case CmdResume:
					paused = false
					fmt.Println("counter resumed")
				case CmdStop:
					fmt.Println("counter stopped")
					return
				}
			}
		}
	}
	fmt.Println("counter finished naturally")
}

关键逻辑说明

  1. 统一控制命令通道:
    替换原有的quit bool通道,改用自定义Command类型的通道,能清晰区分暂停、恢复、停止三种指令,避免单一bool值的局限性。

  2. 运行状态管理:
    主函数中加入isRunning标志,防止重复启动多个计数器goroutine;计数器goroutine退出时通过defer将标志重置为false,保证状态同步。

  3. 暂停/恢复的状态控制:
    在counter函数内部维护paused变量,当收到暂停指令时设为true,此时不再执行计数逻辑,转而阻塞等待恢复或停止命令;收到恢复指令时将paused设为false,继续计数。

  4. 避免空循环占用CPU:
    暂停状态下,通过直接读取通道实现阻塞,避免无意义的空循环消耗CPU资源。

内容的提问来源于stack exchange,提问作者Blankman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 12:45:29