go - 不在控制台上打印接收 channel 值

标签 go

我是 GoLang 的学习者,正在尝试试验和学习同步包和 chan 概念。

Follwoing 是我正在运行并期望在控制台上打印 Receiving Channel Value 的代码,但是该值没有被打印出来,它有时会打印这些值,但并非总是如此。

如果我遍历 chan 而没有将它放入 go 例程中,那么它会打印所有 channel 值但失败并出现错误“fatal error: all goroutines are sleep - deadlock!

我尝试使用 channel “完成”同步 channel 读取,但在那种情况下它再次开始失败并出现相同的错误。我也尝试了 waitGroup API,您可以在我的代码中看到它(已注释),但这对我也不起作用。

感谢帮助

源代码:

package main

import (
    "fmt"
    "sync"
)

type safeOperation struct {
    i int
    sync.Mutex
}

var wg sync.WaitGroup

func main() {
    so := new(safeOperation)
    ch := make(chan int)
    //done := make(chan bool)
    for i := 0; i < 5; i++ {
        go so.Increment(ch)
        go so.Decrement(ch)
    }

    go func() {
        //wg.Add(1)
        for c := range ch {
            fmt.Println("Receiving Channel Value: ", c)
        }
        //wg.Done()
        //done <- true
    }()
    //wg.Wait()
    //<-done
    fmt.Println("Value: ", so.GetValue())
    fmt.Println("Main method finished")
}

func (so *safeOperation) Increment(ch chan int) {
    //so.Lock()
    //defer wg.Done()
    so.i++
    ch <- so.i
    //so.Unlock()
}

func (so *safeOperation) Decrement(ch chan int) {
    //so.Lock()
    //defer wg.Done()
    so.i--
    ch <- so.i
    //so.Unlock()
}

func (so *safeOperation) GetValue() int {
    so.Lock()
    v := so.i
    so.Unlock()
    return v
}

输出: 值:1 主要方法完成

最佳答案

使用 WaitGroup 的一个好模式是在发送到 channel 之前调用 Add() 或使用 go 关键字,然后调用Done() 从 channel 接收后。 通过这种方式,您可以确保 Add() 始终被及时调用,无论是否在 channel block 上发送。

我已经更改了您的示例代码来执行此操作:

package main

import (
    "fmt"
    "sync"
)

type safeOperation struct {
    i int
    sync.Mutex
}

var wg sync.WaitGroup

func main() {
    so := new(safeOperation)
    ch := make(chan int)
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go so.Increment(ch)
        wg.Add(1)
        go so.Decrement(ch)
    }

    go func() {
        for c := range ch {
            fmt.Println("Receiving Channel Value: ", c)
            wg.Done()
        }
    }()
    wg.Wait()
    //<-done
    fmt.Println("Value: ", so.GetValue())
    fmt.Println("Main method finished")
}

func (so *safeOperation) Increment(ch chan int) {
    so.i++
    ch <- so.i
}

func (so *safeOperation) Decrement(ch chan int) {
    so.i--
    ch <- so.i
}

func (so *safeOperation) GetValue() int {
    so.Lock()
    v := so.i
    so.Unlock()
    return v
}

Go playground link

当然,您还想用互斥体保护 safeOperation.i(否则它的值将不可预测),但这就是获得所需输出所必需的。

关于go - 不在控制台上打印接收 channel 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51576115/

相关文章:

go - 如何检查接口(interface)是否是指向 slice 的指针

go - 当客户端关闭连接时,grpc 转到 : how to know in server side,

mongodb - 使用 struct & mongodb/mongo-go-driver 更新/替换 mongodb 文档

go - []接口(interface){}的元素类型

go - 新行分隔的输入流已写入文件

go - 在 golang 中创建静态二进制文件所需的标志

go - interface{} 变量到 []interface{}

go - 如果异常断开,Websocket 会卡住

unit-testing - 如何使用 ` func(w http.ResponseWriter, r *http.Request) `进行模拟测试

go - 无法在现有服务器上使用 go tool pprof