context实现任务停止和启动
最近做了一个需求,在程序一开始的时候抓网卡流量 然后通过一个接口可以修改抓流量的网卡 但是之前我们抓网卡流量的方法是在一开始就运行了,如何实现任务的停止和启动呢 很多时候我们执行一个任务要么就是
context实现任务停止和启动
发布时间:2026-02-25 (2026-02-25)

最近做了一个需求,在程序一开始的时候抓网卡流量

然后通过一个接口可以修改抓流量的网卡

但是之前我们抓网卡流量的方法是在一开始就运行了,如何实现任务的停止和启动呢

很多时候我们执行一个任务要么就是在程序一开始就去启动

例如这样

package main

import (
  "os"
  "os/exec"
)

// 任务的函数
func run() {
  //cmder := "ping baidu.com -n 100"
  cmd := exec.Command("ping", "baidu.com", "-n", "100")
  cmd.Stdout = os.Stdout
  cmd.Run()
}

func main() {
  // 在一开始去执行任务
  run()

}

如果需要动态的启停这个任务,应该怎么实现呢

我们来实操一下

我们执行的这种任务有两种情况

  1. 有自带context的,比如redis命令执行,cmd命令执行,这种实现起来很简单
  2. 没有自带context的,就需要我们自己实现context逻辑

我们先封装一个web来实现任务的停止和启动

package main

import (
  "context"
  "fmt"
  "github.com/gin-gonic/gin"
  "os"
  "os/exec"
)

// 任务的函数
func run() {
  //cmder := "ping baidu.com -n 100"
  cmd := exec.Command("ping", "baidu.com", "-n", "100")
  cmd.Stdout = os.Stdout
  cmd.Run()
}

func main() {
  r := gin.Default()
  r.GET("/start", func(context *gin.Context) {
    context.String(200, "任务启动成功")
  })
  r.GET("/stop", func(context *gin.Context) {
    context.String(200, "任务停止成功")
  })

  r.Run(":8080")
}

自带context的情况

这种实现任务的停止和启动就很简单了

直接使用context.WithCancel返回的cancel取消函数就可以取消任务了

package main

import (
  "context"
  "fmt"
  "github.com/gin-gonic/gin"
  "os"
  "os/exec"
)

var cancel context.CancelFunc

// 任务启动
func startTask() {
  ctx, _cancel := context.WithCancel(context.Background())
  cancel = _cancel
  cmd := exec.CommandContext(ctx, "ping", "baidu.com", "-n", "100")
  cmd.Stdout = os.Stdout
  fmt.Println("开启任务")
  cmd.Run()
}

func stopTask() {
  cancel()
  fmt.Println("任务停止")
}

func main() {
  r := gin.Default()
  r.GET("/start", func(context *gin.Context) {
    go startTask()
    context.String(200, "任务启动成功")
  })
  r.GET("/stop", func(context *gin.Context) {
    stopTask()
    context.String(200, "任务停止成功")
  })

  r.Run(":8080")
}

自己实现context

有些第三方库,或者自己编写的任务可能没有context参数

这个就需要我们自己实现context的功能了

如果是执行系统命令的,我们可以使用exec自带的kill把进程给结束就可以了

package main

import (
  "context"
  "fmt"
  "github.com/gin-gonic/gin"
  "os"
  "os/exec"
)

var cancel context.CancelFunc
var ctx context.Context

// 任务启动
func startTask() {
  ctx, cancel = context.WithCancel(context.Background())

  cmd := exec.Command("ping", "baidu.com", "-n", "100")
  go func() {
    select {
    case <-ctx.Done():
      cmd.Process.Kill()
      fmt.Println("任务被手动停止")
      return
    }
  }()
  cmd.Stdout = os.Stdout
  fmt.Println("开启任务")
  cmd.Run()
}

func stopTask() {
  cancel()
  fmt.Println("任务停止")
}

func main() {
  r := gin.Default()
  r.GET("/start", func(context *gin.Context) {
    go startTask()
    context.String(200, "任务启动成功")
  })
  r.GET("/stop", func(context *gin.Context) {
    stopTask()
    context.String(200, "任务停止成功")
  })

  r.Run(":8080")
}

如果不是执行系统命令这种,比如就是代码里面的循环,就要麻烦一点了

有两种方案,一是使用context,二是使用信号channel

使用context

package main

import (
  "context"
  "fmt"
  "github.com/gin-gonic/gin"
  "time"
)

var cancel context.CancelFunc
var ctx context.Context

// 任务启动
func startTask() {
  ctx, cancel = context.WithCancel(context.Background())
  fmt.Println("开启任务")

  for i := 0; i < 100; i++ {
    select {
    case <-ctx.Done():
      fmt.Println("任务被手动停止")
      return
    default:

    }
    fmt.Println("任务执行中...", i)
    time.Sleep(1 * time.Second)
  }

}

func stopTask() {
  cancel()
  fmt.Println("任务停止")
}

func main() {
  r := gin.Default()
  r.GET("/start", func(context *gin.Context) {
    go startTask()
    context.String(200, "任务启动成功")
  })
  r.GET("/stop", func(context *gin.Context) {
    stopTask()
    context.String(200, "任务停止成功")
  })

  r.Run(":8080")
}

使用channel

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
  "time"
)

var quit chan struct{}

// 任务启动
func startTask() {
  quit = make(chan struct{})
  fmt.Println("开启任务")

  for i := 0; i < 100; i++ {
    select {
    case <-quit:
      fmt.Println("任务被手动停止")
      return
    default:

    }
    fmt.Println("任务执行中...", i)
    time.Sleep(1 * time.Second)
  }

}

func stopTask() {
  close(quit)
  fmt.Println("任务停止")
}

func main() {
  r := gin.Default()
  r.GET("/start", func(context *gin.Context) {
    go startTask()
    context.String(200, "任务启动成功")
  })
  r.GET("/stop", func(context *gin.Context) {
    stopTask()
    context.String(200, "任务停止成功")
  })

  r.Run(":8080")
}