说我有很多字符串,除了常规的sort.Sort和sort.Slice等,我想对它们进行排序。我想使用多个内核来加快处理速度。因此,在阅读大列表时,我将字符串添加到2个不同的切片中,这些字符串以a-m和n-z开头(出于参数考虑)。
同时,我启动了多个go例程来读取通道的字符串切片,然后对它们自己的子列表进行排序。到目前为止,对列表进行了很好的“潜在”并行处理,因此我的排序时间有效地减少了一半。大。现在我的问题是如何将结果返回到主goroutine?
最初,每个goroutine都有2个通道,一个用于传入未排序列表,另一个用于排序列表。是的,它可以工作……但是使用了太多的内存(嘿,我给出了我要为此测试修补的数据量,这可能不是不合理的)。但是后来我想到,在通道上传递切片实际上只是在传递引用,所以我实际上不需要将任何内容传递回来。不必将返回的排序列表放在返回旅程的通道中,显然在记忆力上要少得多,但是(对我来说)有气味。
这意味着我可以将其中一个goroutine进行分类,而主要的goroutine(理论上)可以操纵相同的列表。只要遵守纪律就不会成为问题,但显然仍然是一个问题。在Go中是否有公认的最佳实践来说明不应将引用作为输入从一个goroutine传递给另一个goroutine ....但是可以接受的是,可以通过通道返回生成参考数据的goroutine(因为goroutine可以停止使用参考)。
[在有人说之前,是的,我知道我不必通过渠道等将它们传递给我,但这只是我正在修补并让我思考的情况。
我知道波浪形和波浪形。这是显示上面代码的最小代码子集。
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strings"
"sync"
"time"
)
var wg sync.WaitGroup
func sortWordsList(id int, ch chan []string ) {
l := <- ch
sort.Strings(l)
wg.Done()
}
func main() {
file, err := os.Open("big.txt")
defer file.Close()
if err != nil {
fmt.Printf("BOOM %s\n", err.Error())
panic(err)
}
// Start reading from the file with a reader.
reader := bufio.NewReader(file)
inCh1 := make(chan []string, 1000)
inCh2 := make(chan []string, 1000)
go sortWordsList(1, inCh1)
go sortWordsList(2, inCh2)
wg.Add(2)
words1 := []string{}
words2 := []string{}
for {
line, err := reader.ReadString('\n')
if err != nil {
break
}
sp := strings.Split(line, " ")
for _,w := range sp {
word := strings.ToLower(w)
word = strings.TrimSuffix(word, "\n")
if len(word) > 0 {
// figure out where to go.
// arbitrary split.
if word[0] < 'm' {
words1 = append(words1, word)
} else {
words2 = append(words2, word)
}
}
}
}
inCh1 <- words1
inCh2 <- words2
close(inCh1)
close(inCh2)
wg.Wait()
// now have sorted words1 and words2 slices.
}
传递引用没有错。只要您同步对引用的访问,就可以传递引用并在发送goroutine中继续使用它。对于数组或大型结构之类的大型对象,传递引用通常是避免昂贵拷贝的合理做法。另外,避免传递引用意味着避免传递切片和图或包含切片,图或对其他结构的引用的任何内容。
您已经知道,您实际上并不需要通道,只需在构造切片后启动goroutine,然后直接传递切片即可。
go sortWordsList(words1)
go sortWordsList(words2)
或:
go sort.Strings(words1)
go sort.Strings(words2)