在控制台上不打印接收通道值

时间:2018-07-28 23:51:52

标签: go

我是GoLang的学习者,正在尝试进行实验并了解Sync软件包和chan概念。

我正在运行并希望在控制台上打印接收通道值的代码,但是该值未得到打印,它有时但并非总是打印该值。

如果我在不使用chan的情况下进行调整,那么它将打印所有通道值,但会失败,并显示错误“ 致命错误:所有goroutine都在睡眠中-死锁!

我尝试使用通道“完成”来同步通道读取,但是在这种情况下,它再次因相同的错误而开始失败。我还尝试了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 主要方法完成

1 个答案:

答案 0 :(得分:2)

使用WaitGroup的一个好方法是在发送到频道之前调用Add()或使用go关键字,并在从频道接收后调用Done()。 这样,您可以确定Add()总是按时调用,而不管是否在通道块上发送。

我已更改您的示例代码来做到这一点:

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(否则其值将不可预测),但这是获得所需输出所必需的。