[日常] Go语言圣经-竞争条件习题
发布日期:2021-05-18 07:59:28 浏览次数:21 分类:精选文章

本文共 2871 字,大约阅读时间需要 9 分钟。

=Golang程序优化指南=

在设计并发程序时,确保数据安全和正确性至关重要。以下优化版本解决了原程序可能引起的数据丢失问题,并确保了程序的健壮性:

=[版本1] 取款安全 isolate financial operations in a goroutine

package mainimport (    "fmt"    "sync")var balance intfunc Deposit(amount int) {    // 在一个 goroutine 中限制总余额    if balance < 0 {        // 如果客户的钱跑掉了,不再处理其他交易        // prevent negative balance        balance = 0    }    balance += amount}func Balance() int {    return balance}func main() {    var wg sync.WaitGroup    // 告知 teller goroutine 开始一个新的交易    teller()    // Alice 的操作    go func() {        defer wg.Done()        Deposit(200)        fmt.Printf("Alice: %d\n", Balance())    }()    // Bob 的操作    go func() {        defer wg.Done()        Deposit(100)    }()    // 售款操作示例    go func() {        defer wg.Done()        res := Withdraw(100)        if !res {            fmt.Printf("未能取款\n")        } else {            fmt.Printf("取款成功\n")        }    }()    // 等待所有 goroutine 完成    wg.Wait()    // 最终的余额检查    fmt.Printf("最终余额: %d\n", Balance())}// 新增函数:示例的取款函数func Withdraw(amount int) bool {    // 尝试取款    Deposit(-amount)    if Balance() < 0 {        // 如果有负额,尝试恢复        Deposit(amount)        return false // 没有足够的资金    }    return true}// teller goroutine 用于协调所有交易func teller() {    var balance int    for {        select {        case amount := <- deposits:            if balance < 0 {                balance = 0            }            balance += amount        case balances := <- balances:            // 等待余额更新        }    }}

=[版本2] 优化后的代码结构

package mainimport (    "fmt"    "sync")var deposits = make(chan int, 10) // 最大同时存款数量var balances = make(chan int, 10) // 最大同时查询数量func Deposit(amount int) {    deposits <- amount}func Balance() int {    return <-balances}func main() {    var wg sync.WaitGroup    // 初始化一个 teller goroutine    teller()    // 示例存款操作    go func() {        defer wg.Done()        Deposit(200)        fmt.Printf("存款成功: 200\n")    }()    // 示例查询操作    go func() {        defer wg.Done()        fmt.Printf("当前余额: %d\n", Balance())    }()    // 售款操作示例    go func() {        defer wg.Done()        res := Withdraw(100)        if !res {            fmt.Printf("取款失败\n")        } else {            fmt.Printf("取款成功\n")        }    }()    // 等待所有操作完成    wg.Wait()    // 最终检查余额    fmt.Printf("系统最终余额: %d\n", Balance())}// teller goroutine 用于处理并发交易func teller() {    var balance int    for {        select {        case amount := <- deposits:            if balance < 0 {                balance = 0            }            balance += amount        case <- balances:            // 等待同时查询处理        }    }}// 新增函数:实现取款功能func Withdraw(amount int) bool {    // 尝试取款    Deposit(-amount)    if Balance() < 0 {        // 恢复资金失败,返回 false        return false    }    return true}

以上代码结合了 channel 通讯机制,确保了在多 goroutine 环境下同时操作的安全性。 teller goroutine 用于协调余额更新,避免了不同 goroutine 比赛读取和写入问题。同时,每个 goroutine 都使用 waitgroup 进行协调,确保代码整体同步有序运行。

上一篇:[日常] Go语言圣经-并发的非阻塞缓存
下一篇:[日常] 高性能MySQL-索引

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年04月24日 15时17分05秒