Go 戈朗股市的止损行为

Go 戈朗股市的止损行为,go,ticker,Go,Ticker,如果我在股票行情频道上进行测距并呼叫停止,则该频道将停止,但不会关闭 在本例中: package main import ( "time" "log" ) func main() { ticker := time.NewTicker(1 * time.Second) go func(){ for _ = range ticker.C { log.Println("tick") } log.

如果我在股票行情频道上进行测距并呼叫停止,则该频道将停止,但不会关闭

在本例中:

package main

import (
    "time"
    "log"
)

func main() {
    ticker := time.NewTicker(1 * time.Second)
    go func(){
        for _ = range ticker.C {
            log.Println("tick")
        }
        log.Println("stopped")
    }()
    time.Sleep(3 * time.Second)
    log.Println("stopping ticker")
    ticker.Stop()
    time.Sleep(3 * time.Second)
}
运行产生:

2013/07/22 14:26:53 tick
2013/07/22 14:26:54 tick
2013/07/22 14:26:55 tick
2013/07/22 14:26:55 stopping ticker

这样goroutine就永远不会离开了。有没有更好的办法来处理这个案子?我是否应该关心goroutine从未退出?

在第二个频道上发送信号完成,并在您的goroutine中在ticker和done频道之间选择


根据您真正想要做的事情,可能存在一个更好的解决方案,但从减少的演示代码中很难看出这一点。

使用了Volker建议的第二个频道。这就是我最后跑步的原因:

package main

import (
    "log"
    "time"
)

// Run the function every tick
// Return false from the func to stop the ticker
func Every(duration time.Duration, work func(time.Time) bool) chan bool {
    ticker := time.NewTicker(duration)
    stop := make(chan bool, 1)

    go func() {
        defer log.Println("ticker stopped")
        for {
            select {
            case time := <-ticker.C:
                if !work(time) {
                    stop <- true
                }
            case <-stop:
                return
            }
        }
    }()

    return stop
}

func main() {
    stop := Every(1*time.Second, func(time.Time) bool {
        log.Println("tick")
        return true
    })

    time.Sleep(3 * time.Second)
    log.Println("stopping ticker")
    stop <- true
    time.Sleep(3 * time.Second)
}

如果需要节省更多空间,请使用空structs-struct{}通道,它不需要占用内存。如上所述,不要在里面发送东西,只需关闭,实际上发送的是零值。

你可以这样做

package main

import (
    "fmt"
    "time"
)

func startTicker(f func()) chan bool {
    done := make(chan bool, 1)
    go func() {
        ticker := time.NewTicker(time.Second * 1)
        defer ticker.Stop()
        for {
            select {
            case <-ticker.C:
                f()
            case <-done:
                fmt.Println("done")
                return
            }
        }
    }()
    return done
}

func main() {
    done := startTicker(func() {
        fmt.Println("tick...")
    })
    time.Sleep(5 * time.Second)
    close(done)
    time.Sleep(5 * time.Second)
}

如果go例程没有退出,就会出现内存泄漏。调用closeticker.C释放Go例程。无法关闭:无法关闭仅接收通道golang docs应该对此进行扩展,但他们的Ticker示例显示了如何使用done通道确保没有Go例程泄漏:如果您的工作需要4秒,您将使goroutine死锁,并且它将被困在尝试写入其唯一读取器的通道中。您只需要在for{}上设置一个状态变量,而不在stop通道上发送,只需关闭它即可。此外,nil通道是在退出操作后发出信号的一种很好的方法。closequit到任何其他通道读取:参见vs.a。不确定为什么会被否决:quit:=makechan struct{}是一项伟大的技术,它清楚地表明了通道的用途,即通过closequit发出关闭信号