go - 管理后台操作(创建/杀死)

标签 go concurrency kill

我第一次在这里发帖,因为我在互联网上找不到干净的解决方案。

我的目标很简单,我需要创建 一个 后台操作 (goroutine 或进程或其他...)我可以 正确杀死 (不要留在后台)。

我尝试了很多事情,比如使用 chan 或 context。

但我永远找不到避免泄漏的正确方法。

这是一个例子:

package main

import (
    "log"
    "strconv"
    "runtime"
    "time"
    "math/rand"
)

func main() {
    log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()))
    func1()
    leak := ""
    if runtime.NumGoroutine() > 1 {
        leak = " there is one LEAK !!"
    }
    log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()) + leak)
}

func func1() {

    done := make(chan struct{})
    quit := make(chan struct{})

    go func() {

        log.Println("goroutines: " + strconv.Itoa(runtime.NumGoroutine()))

        select {
        case <-quit:
            log.Println("USEFUL ???")
            return
        default:
            func2()
            done<-struct{}{}
        }
    }()

    select {
    case <-time.After(4 * time.Second):
        quit<-struct{}{}
        log.Println("TIMEOUT")
    case <-done:
        log.Println("NO TIMEOUT")
    }
}

func func2() {
    log.Println("JOB START")

    rand.Seed(time.Now().UnixNano())
    val := rand.Intn(10)
    log.Println("JOB DURATION: " + strconv.Itoa(val))
    time.Sleep(time.Duration(val) * time.Second) // fake a long process with an unknown duration

    log.Println("JOB DONE")
}

在这个例子中,如果工作在 4 秒超时之前完成,一切都很好,goroutine 的最终数量将为 1,否则它将像我能找到的每个示例一样为 2。

但这只是一个例子,也许使用 goroutines 不可能,也许在 Go 中甚至不可能。

最佳答案

你的问题在这里:

quit := make(chan struct{})

go func() {
    for {
        select {
        case <-quit:
            log.Println("USEFUL ???")
            return
        default:
            func2()
            quit<-struct{}{}
            return
        }
    }
}()

这个 goroutine 在 上发出信号无缓冲 channel 。这意味着当它到达 quit<-struct{}{} ,该发送将永远阻塞,因为它正在等待自己接收。不过,尚不完全清楚这是如何工作的。这里发生了一些奇怪的事情:
  • goroutine 通过 channel 向自己发送信号,这似乎是错误的 - 它不需要与自己通信
  • channel 和循环似乎没有必要; quit<-struct{}{}可以替换为 log.Println("USEFUL ???")并且可以删除整个 for/select/channel 业务
  • 该函数在每个 case 中返回的select , 所以把它放在一个循环中是没有意义的 - 没有任何场景可以让这个代码执行循环的第二次迭代
  • 关于go - 管理后台操作(创建/杀死),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61952220/

    相关文章:

    go - 使用文件方案读取 url 作为 ReadFile 文件名的惯用方法是什么?

    java - 如何在Java中实现对映射到内存的文件的并发读取?

    linux - 无法从 Makefile 执行 shell 命令

    go - 如何通过不同的结构来发挥作用?

    go - go微服务中如何给每条日志添加trace id

    C++ 11 unordered_map 段错误

    linux - 重定向标准输入以完全不提供输入?

    android - 如何以编程方式停止(强制停止)其他应用程序 Android?

    go - 如何有效地将 channel 链接在一起?

    c++ - 并发/多线程:是否可以通过这种方式生成相同的输出?