V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
blackcurrant
V2EX  ›  Go 编程语言

golang 中如何通过一个 http 请求触发一个长时间运行的函数?

  •  
  •   blackcurrant · 2019-08-30 10:58:54 +08:00 · 3453 次点击
    这是一个创建于 1913 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这里的 doSomething 可能会因为 http 超时或者各种原因中断,如何让 longTimeTask() 持续运行下去呢?

    func doSomething(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "start!\n")
        longTimeTask()
    }
    
    func longTimeTask() {
        ...
    }
    
    func main() {
        http.HandleFunc("/do", doSomething)
        err := http.ListenAndServe(":12345", nil)
        if err != nil {
            log.Fatal("ListenAndServe: ", err)
        }
    }
    
    12 条回复    2019-10-14 20:26:37 +08:00
    Trim21
        1
    Trim21  
       2019-08-30 11:01:39 +08:00 via iPhone   ❤️ 1
    新开一个 goroutine ?
    blackcurrant
        2
    blackcurrant  
    OP
       2019-08-30 11:05:30 +08:00
    @Trim21 你是说这样?
    func doSomething(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "start!\n")
    go longTimeTask()
    }

    当 doSomething 退出,函数里面的 goroutine 也退出了。
    lbp0200
        3
    lbp0200  
       2019-08-30 11:39:20 +08:00   ❤️ 1
    func longTimeTask() {
    go func() {
    tick := time.Tick(time.Second)
    for range tick {
    log.Println("fucker")
    }
    }()
    }

    结果:
    curl 127.0.0.1:12345/do [11:37:17]
    start!

    2019/08/30 11:37:21 fucker
    2019/08/30 11:37:22 fucker
    2019/08/30 11:37:23 fucker
    2019/08/30 11:37:24 fucker
    2019/08/30 11:37:25 fucker
    2019/08/30 11:37:26 fucker
    2019/08/30 11:37:27 fucker
    2019/08/30 11:37:28 fucker
    2019/08/30 11:37:29 fucker
    2019/08/30 11:37:30 fucker
    2019/08/30 11:37:31 fucker
    2019/08/30 11:37:32 fucker
    ……
    fuxiaohei
        4
    fuxiaohei  
       2019-08-30 11:57:55 +08:00   ❤️ 1
    @blackcurrant 你最好试一下再说
    wkzq
        5
    wkzq  
       2019-08-30 12:30:19 +08:00   ❤️ 1
    建议用 channel 触发 goroutine, 这样子可以通过调节 sigChan 的 size 来控制 goroutine 的数量

    func doSomething(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "start!\n")
    sigChan <- 1
    }

    func goroutine() {
    for {
    select {
    case _ = <- sigChan:
    go longTimeTask()
    }
    }
    }

    func longTimeTask() {
    ...
    }
    blackcurrant
        6
    blackcurrant  
    OP
       2019-08-30 12:31:08 +08:00
    @lbp0200
    @fuxiaohei
    真的可以!看来自己对 goroutine 理解不够。
    zzlettle
        7
    zzlettle  
       2019-08-30 13:21:58 +08:00
    意思是函数退出了
    协程依然在运行
    看来我也对 GO 协程理解不到位
    buried
        8
    buried  
       2019-08-30 13:28:53 +08:00
    三楼的回答有声音怎么回事
    zzlettle
        9
    zzlettle  
       2019-08-30 13:31:06 +08:00
    这个也解开了我以前的一个提问
    当时用时时间定时器
    很奇怪,函数推出
    然后还显示了协程里面的内容
    现在知道了,原来是时间定时器那个协程还能在运行的原因
    labulaka521
        10
    labulaka521  
       2019-08-30 13:37:00 +08:00 via Android
    @blackcurrant 不会的 建议看下 go 的调度
    fishofcat
        11
    fishofcat  
       2019-08-30 13:37:46 +08:00
    @blackcurrant 你最好试试再说
    vtz668
        12
    vtz668  
       2019-10-14 20:26:37 +08:00   ❤️ 1
    我之前写了一个求素数的,当值特别大时,运行时间要好久,10 几秒把,后来我用 grpc 调用,无论这个值多大,运行一二十秒,结果也会顺利得到,后来我用 http 调用,刚开始我以为我是用微服务 micro 做得,api 负责处理 http 请求,然后再调用 grpc 调用方法求素数,这时候如果超时 5 秒,就会报错,但是 grpc 调用的代码依旧在运行,后来我就搜索英文和中文,因为我不知道是 micro 框架限定超时时间还是注册服务 consul,但是没收到,后来我无意中在那里看到有人回复说,是 http 里面 ctx 会默认 timeout 时间为 5 秒,所以应该是这个问题,因为就算开启一个协程,http 在 5 秒内没有得到结果,也会返回
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2651 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:55 · PVG 18:55 · LAX 02:55 · JFK 05:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.