我很难理解并发/并行。在我的代码中,我做了一个5个循环的循环。在循环内部,我添加了wg.Add(1),总共有5个Add。这是代码:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var list []int
    wg := sync.WaitGroup{}
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(c *[]int, i int) {
            *c = append(*c, i)
            wg.Done()
        }(&list, i)
    }
    wg.Wait()
    fmt.Println(len(list))
}

主函数等待所有goroutine完成,但是当我尝试打印slice的长度时,会得到随机结果。 ex(1,3,etc)是否缺少某些东西才能获得预期的结果,即5?

最佳答案

获得预期结果(例如5)是否缺少某些东西?

是的,正确的同步。如果多个goroutine在其中至少一个为写操作的情况下访问同一个变量,则需要显式同步。

您的示例可以使用单个互斥锁“保护”:

var list []int
wg := sync.WaitGroup{}

mu := &sync.Mutex{} // A mutex

for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(c *[]int, i int) {
        mu.Lock() // Must lock before accessing shared resource
        *c = append(*c, i)
        mu.Unlock() // Unlock when we're done with it
        wg.Done()
    }(&list, i)
}
wg.Wait()

fmt.Println(len(list))

这将始终打印5。

注意:最后读取同一片以打印其长度,但此处未使用互斥锁。这是因为使用waitgroup可以确保我们只能在所有修改它的goroutine完成其工作之后才能到达该点,因此数据争用不会在那里发生。但通常来说,读取和写入都必须同步。

查看可能的重复项:

go routine not collecting all objects from channel

Server instances with multiple users

Why does this code cause data race?

How safe are Golang maps for concurrent Read/Write operations?

golang struct concurrent read and write without Lock is also running ok?

查看相关问题:

Can I concurrently write different slice elements

If I am using channels properly should I need to use mutexes?

Is it safe to read a function pointer concurrently without a lock?

Concurrent access to maps with 'range' in Go

09-05 16:09