使用 Channels 和 WaitGroup 时所有 GoRoutines 上的死锁
Deadlock on All GoRoutines When Using Channels and WaitGroup
我是 Go 的新手,目前正在尝试 运行 创建文件的函数和 returns 它的文件名,并同时具有此 运行。
我决定尝试使用 goroutines 和 WaitGroup 来完成它。当我使用这种方法时,我最终得到的列表大小比输入大小小几百个文件。例如。对于 5,000 个文件,我创建了大约 4,700~ 个文件。
我认为这是由于某些竞争条件造成的:
wg := sync.WaitGroup{}
filenames := make([]string, 0)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
filenames = append(filenames, createFile())
}()
}
wg.Wait()
return filenames, nil
不要通过共享内存来交流;通过通信共享内存。
我尝试使用通道“通过通信共享内存”。每当我这样做时,似乎都会出现僵局,我似乎无法理解为什么。谁能给我指出正确的方向,让我正确地一起使用通道和等待组,以便将所有创建的文件保存到共享数据结构中?
这是为我产生死锁的代码(致命错误:所有 goroutines 都睡着了 - 死锁!):
wg := sync.WaitGroup{}
filenames := make([]string, 0)
ch := make(chan string)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ch <- createFile()
}()
}
wg.Wait()
for i := range ch {
filenames = append(filenames, i)
}
return filenames, nil
谢谢!
第一个有一场比赛。您必须保护对 filenames
:
的访问
mu:=sync.Mutex{}
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
filenames = append(filenames, createFile())
}()
}
对于第二种情况,您正在等待 goroutines 完成,但是 goroutines 只能在您从通道读取后才能完成,所以死锁。您可以通过在单独的 goroutine 中读取频道来修复它。
go func() {
for i := range ch {
filenames = append(filenames, i)
}
}()
wg.Wait()
close(ch) // Required, so the goroutine can terminate
return filenames, nil
有lock-free版本,如果文件数固定:
filenames := make([]string, totalFiles)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
filenames[index]=createFile()
}(i)
}
wg.Wait()
我是 Go 的新手,目前正在尝试 运行 创建文件的函数和 returns 它的文件名,并同时具有此 运行。
我决定尝试使用 goroutines 和 WaitGroup 来完成它。当我使用这种方法时,我最终得到的列表大小比输入大小小几百个文件。例如。对于 5,000 个文件,我创建了大约 4,700~ 个文件。
我认为这是由于某些竞争条件造成的:
wg := sync.WaitGroup{}
filenames := make([]string, 0)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
filenames = append(filenames, createFile())
}()
}
wg.Wait()
return filenames, nil
不要通过共享内存来交流;通过通信共享内存。
我尝试使用通道“通过通信共享内存”。每当我这样做时,似乎都会出现僵局,我似乎无法理解为什么。谁能给我指出正确的方向,让我正确地一起使用通道和等待组,以便将所有创建的文件保存到共享数据结构中?
这是为我产生死锁的代码(致命错误:所有 goroutines 都睡着了 - 死锁!):
wg := sync.WaitGroup{}
filenames := make([]string, 0)
ch := make(chan string)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ch <- createFile()
}()
}
wg.Wait()
for i := range ch {
filenames = append(filenames, i)
}
return filenames, nil
谢谢!
第一个有一场比赛。您必须保护对 filenames
:
mu:=sync.Mutex{}
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
filenames = append(filenames, createFile())
}()
}
对于第二种情况,您正在等待 goroutines 完成,但是 goroutines 只能在您从通道读取后才能完成,所以死锁。您可以通过在单独的 goroutine 中读取频道来修复它。
go func() {
for i := range ch {
filenames = append(filenames, i)
}
}()
wg.Wait()
close(ch) // Required, so the goroutine can terminate
return filenames, nil
有lock-free版本,如果文件数固定:
filenames := make([]string, totalFiles)
for i := 0; i < totalFiles; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
filenames[index]=createFile()
}(i)
}
wg.Wait()