猿问

通道中缺少数据

我写了一个小程序来练习go channel。


package main


import (

    "log"

    "strconv"

)


var MaxOutstanding int = 1

var channelSize int = 10

var sem = make(chan int, MaxOutstanding)


type Request struct {

    command string

    data    string

}


func process(req *Request) {

    log.Println(req)

}


func serve(reqs chan *Request) {

    for req := range reqs {

        sem <- 1

        go func() {

            process(req)

            <-sem

        }()

    }

}


func main() {

    reqs := make(chan *Request, channelSize)

    for i := 0; i < channelSize; i++ {

        req := &Request{"start", strconv.Itoa(i)}

        reqs <- req

    }

    close(reqs)

    serve(reqs)

}

这打印


2018/12/02 16:52:30 &{start 1}

2018/12/02 16:52:30 &{start 2}

2018/12/02 16:52:30 &{start 3}

2018/12/02 16:52:30 &{start 4}

2018/12/02 16:52:30 &{start 5}

2018/12/02 16:52:30 &{start 6}

2018/12/02 16:52:30 &{start 7}

2018/12/02 16:52:30 &{start 8}

2018/12/02 16:52:30 &{start 9}

因此,不会打印 &{start 0}。为什么这个不见了?


料青山看我应如是
浏览 103回答 2
2回答

斯蒂芬大帝

因为在serve()你的循环变量中使用了你在一个单独的 goroutine 上执行的函数文字,它被运行循环的 goroutine 同时修改:数据竞争。如果您有数据竞争,则行为是未定义的。如果您复制变量,它将起作用:for req := range reqs {    sem <- 1    req2 := req    go func() {        process(req2)        <-sem    }()}在Go Playground上尝试一下。另一种可能性是将其作为参数传递给匿名函数:for req := range reqs {    sem <- 1    go func(req *Request) {        process(req)        <-sem    }(req)}在Go Playground试试这个。

拉丁的传说

这是因为当匿名执行时,请求已经从移动Request{0}到Request{1},所以你打印从{start 1}。// method 1: add a parameter, pass it to anonymous functionfunc serve(reqs chan *Request) {&nbsp; &nbsp; for req := range reqs {&nbsp; &nbsp; &nbsp; &nbsp; sem <- 1&nbsp; &nbsp; &nbsp; &nbsp; // You should make the req as parameter of this function&nbsp; &nbsp; &nbsp; &nbsp; // or, when the function execute, the req point to Request{1}&nbsp; &nbsp; &nbsp; &nbsp; go func(dup *Request) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; process(dup)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <-sem&nbsp; &nbsp; &nbsp; &nbsp; }(req)&nbsp; &nbsp; }&nbsp; &nbsp; // And you should wait for the Request{9} to be processed&nbsp; &nbsp; time.Sleep(time.Second)}// method 2: make for wait anonymous functionfunc serve(reqs chan *Request) {&nbsp; &nbsp; for req := range reqs {&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; process(req)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sem <- 1&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; // Or wait here&nbsp; &nbsp; &nbsp; &nbsp; <-sem&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答