超时后退出goroutine

超时后退出goroutine,go,concurrency,goroutine,Go,Concurrency,Goroutine,我正试图在go中编写一个类似于cron的程序,其中增加了一个功能,即为作业提供一个max runtime,如果某个函数超过此持续时间,则该作业应该退出。以下是我的全部代码: package main import ( "fmt" "log" "sync" "time" ) type Job struct { ID string MaxRuntime

我正试图在go中编写一个类似于cron的程序,其中增加了一个功能,即为作业提供一个max runtime,如果某个函数超过此持续时间,则该作业应该退出。以下是我的全部代码:

package main

import (
    "fmt"
    "log"
    "sync"
    "time"
)

type Job struct {
    ID         string
    MaxRuntime time.Duration
    Frequency  time.Duration
    Function   func()
}

func testFunc() {
    log.Println("OPP11")
    time.Sleep(7 * time.Second)
    log.Println("OP222")
}

func New(ID, frequency, runtime string, implementation func()) Job {
    r, err := time.ParseDuration(runtime)

    if err != nil {
        panic(err)
    }

    f, err := time.ParseDuration(frequency)

    if err != nil {
        panic(err)
    }

    j := Job{ID: ID, MaxRuntime: r, Frequency: f, Function: implementation}
    log.Printf("Created job %#v with frequency %v and max runtime %v", ID, f, r)
    return j
}

func (j Job) Run() {

    for range time.Tick(j.Frequency) {
        start := time.Now()
        log.Printf("Job %#v executing...", j.ID)
        done := make(chan int)
        //quit := make(chan int)
        //var wg sync.WaitGroup
        //wg.Add(1)

        go func() {
          j.Function()
          done <- 0
        }()

        select {
        case <-done:
            elapsed := time.Since(start)
            log.Printf("Job %#v completed in %v \n", j.ID, elapsed)
        case <-time.After(j.MaxRuntime):
            log.Printf("Job %#v halted after %v", j.ID, j.MaxRuntime)
            // here should exit the above goroutine
        }
    }

}

func main() {
    // create a new job given its name, frequency, max runtime
    // and the function it should run
    testJob := New("my-first-job", "3s", "5s", func() {
        testFunc()
    })

    testJob.Run()
}
主程序包
进口(
“fmt”
“日志”
“同步”
“时间”
)
类型作业结构{
ID字符串
MaxRuntime.Duration
频率、时间、持续时间
函数func()
}
func testFunc(){
log.Println(“OPP11”)
时间。睡眠(7*时间。秒)
log.Println(“OP222”)
}
func新(ID、频率、运行时字符串、实现func())作业{
r、 错误:=time.ParseDuration(运行时)
如果错误!=零{
恐慌(错误)
}
f、 错误:=时间。解析持续时间(频率)
如果错误!=零{
恐慌(错误)
}
j:=作业{ID:ID,MaxRuntime:r,频率:f,函数:实现}
log.Printf(“已创建作业%#v,频率为%v,最大运行时间为%v”,ID、f、r)
返回j
}
func(j作业)运行(){
对于范围时间。勾选(j.频率){
开始:=时间。现在()
log.Printf(“作业%#v正在执行…”,j.ID)
完成:=制造(成交量)
//退出:=make(chan int)
//var wg sync.WaitGroup
//工作组.添加(1)
go func(){
j、 函数()

完成如注释中所述,整个问题在于您想要取消不可取消的函数(
j.function
)的执行

没有办法“杀死一个goroutine”。goroutine以一种合作的方式工作。如果你想“杀死它”,你需要确保在该goroutine中运行的函数有一种机制,让你发出信号,它应该停止它正在做的事情并返回,让运行它的goroutine最终终止

表示函数可取消的标准方法是将
context.context
作为其第一个参数:

类型作业结构{
// ...
函数func(context.context)
}

然后创建上下文并将其传递给
j.Function
。由于取消逻辑仅基于超时,因此无需编写所有
select…如果您无法检查
@Jimb是的,我知道,
函数
应该是一个通用函数,由用户传递,因此我无法添加任何c取消它内部的逻辑。没有办法杀死一个goroutine,那么问题到底是什么?根本没有办法做到这一点?甚至不使用
上下文。WithTimeout
?我现在正在研究
上下文。WithTimeout
只是给你
一个更好的方法
go func() {
    for {
        select {
        case <-quit:
            fmt.Println("quiting goroutine")
            return
        default:
            j.Function()
            done <- 0
        }
    }
}()