登录
首页 >  Golang >  Go问答

出现意外行为的同步代码实现

来源:stackoverflow

时间:2024-02-24 22:09:23 328浏览 收藏

知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《出现意外行为的同步代码实现》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!

问题内容

下面是我在学习 golang 中的 goroutine 时正在研究的一个示例。在下面的代码中,我们生成 30 个 goroutine,每个 goroutine 都访问一个名为ordersprocessed 的共享变量。该示例代表收银员处理订单。一旦ordersprocessed 超过 10,我们就会打印出收银员无法接受更多订单。

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var (
      wg sync.waitgroup
      ordersprocessed int64
    )
    // this does not work as expected
    cashier := func(ordernum int) {
        value := atomic.loadint64(&ordersprocessed)
        fmt.println("value is ", value)
        if value < 10 {
            // cashier is ready to serve!
            fmt.println("proessing order", ordernum)
            atomic.addint64(&ordersprocessed, 1)
        } else {
            // cashier has reached the max capacity of processing orders.
            fmt.println("i am tired! i want to take rest!", ordernum)
        }
        wg.done()
    }

    for i := 0; i < 30; i++ {
        wg.add(1)
        go func(ordernum int) {
            // making an order
            cashier(ordernum)
        }(i)

    }
    wg.wait()
}

我希望看到 10 个订单的已处理消息,但此后无法处理。不过,这 30 个订单都会得到处理。我使用了sync/atomic包来同步对ordersprocessed变量的访问,但是它的值总是被每个goroutine读取为0。但是,如果我将上面的代码更改为使用互斥锁,如下所示,它将按预期工作:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var (
       wg sync.WaitGroup
       ordersProcessed int64
       mutex sync.Mutex
    )
    // This works as expected
    cashier := func(orderNum int) {
        mutex.Lock()
        if ordersProcessed < 10 {
            // Cashier is ready to serve!
            fmt.Println("Processing order", orderNum)
            ordersProcessed++
        } else {
            // Cashier has reached the max capacity of processing orders.
            fmt.Println("I am tired! I want to take rest!", orderNum)
        }
        mutex.Unlock()
        wg.Done()
    }

    for i := 0; i < 30; i++ {
        wg.Add(1)
        go func(orderNum int) {
            // Making an order
            cashier(orderNum)
        }(i)

    }
    wg.Wait()
}

有人可以告诉我我使用sync/atomic包同步对ordersprocessed变量的访问的方式有什么问题吗?


解决方案


您使用了sync/atomic包,但没有同步goroutines。

当你启动 30 个 Goroutine 时,每个 Goroutine 首先读取共享变量并递增它。如果所有 goroutine 都读取该变量,它们都会读取 0。这里的问题是,当一个 goroutine 正在处理该变量时,您没有阻止其他 goroutine 修改该变量。程序运行后,共享变量可以是 10 到 30 之间的任意值,具体取决于 goroutine 的交错方式。

您的第二个实现是正确的,它可以防止其他 goroutine 在其中一个 goroutine 正在处理共享变量时读取和修改共享变量。

理论要掌握,实操不能落!以上关于《出现意外行为的同步代码实现》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>