go - goroutine 中的代码块产生奇怪的错误结果

标签 go goroutine

我有一个很大的 N*1 名字数组
我目前正在使用 goroutine 来计算名称之间的编辑距离

问题是 [B] [C] 的结果不同,可能像

ABC BCD 7
ABC BCD 3

姓名有20000条记录

var names []string

将名字分成两 block

nameCount := len(names)  
procs := 2  
chunkSize := nameCount / procs 

channel

ch := make(chan int)  
var wg sync.WaitGroup


for i := 0; i < procs; i++ { //create two goroutines
    start := i * chunkSize
    end := (i+1)*chunkSize - 1
    fmt.Println(start, end) //get slice start and end
    wg.Add(1)
    go func(slices []string, allnames []string) {
        for _, slice := range slices {
            minDistance = 256
            distance := 0
            sum := 0
            for _, name := range allnames {
                distance = calcEditDist(slice, name) //get the LD [A]
                sum += 1
                if distance > 0 && distance < minDistance {
                    minDistance = distance
                    fmt.Println(slice, name, distance) //[B]
                    fmt.Println(slice, name, calcEditDist(slice, name)) //[C]
                } else if distance == minDistance {
                    fmt.Println(slice, name, distance)
                    fmt.Println(slice, name, calcEditDist(slice, name))
                }
            }
            // for _, name := range allnames {
            //  fmt.Println(slice, name)
            // }
            ch <- sum
            // fmt.Println(len(allnames), slice)
            break
        }
        wg.Done()
    }(names[start:end], names)
}

我把 calcEditDist 放在了@https://github.com/copywrite/keyboardDistance/blob/master/parallel.go

附言:
如果我声明

var dp [max][max]int

在 calcEditDist 中作为局部变量而不是全局变量,结果是正确的,但是非常慢

更新 1
谢谢所有 friend ,我分三步采纳下面的好建议
1) 我将 dp 缩小到一个更合理的大小,比如 100 甚至更小,完成
2) 我把 dp 声明放在每个 goroutine 中,并像 Nick 说的那样传递它的指针,DONE
3) 稍后我将尝试动态分配 dp,稍后

性能急剧提升,╰(°▽°)╯

最佳答案

正如您在帖子中指出的那样,将 dp 作为全局变量是问题所在。

每次在 CalcEditDistance 中分配它太慢了。

您有两种可能的解决方案。

1) 每个 go-routine 只需要 1 个 dp 数组,所以在 for loop 循环中分配它并传递一个指向它的指针(不要直接传递数组,因为数组按值传递这将涉及大量复制!)

for i := 0; i < procs; i++ { //create two goroutines
    start := i * chunkSize
    end := (i+1)*chunkSize - 1
    fmt.Println(start, end) //get slice start and end
    wg.Add(1)
    go func(slices []string, allnames []string) {
        var dp [max][max]int // allocate
        for _, slice := range slices {
            minDistance = 256
            distance := 0
            sum := 0
            for _, name := range allnames {
                distance = calcEditDist(slice, name, &dp) // pass dp pointer here

更改 calcEditDist 以获取 dp

func CalcEditDist(A string, B string, dp *[max][max]int) int {
        lenA := len(A)
        lenB := len(B)

2) 重写您的 calcEditDistance,这样它就不需要庞大的 O(N^2) dp 数组。

如果您仔细研究该函数,它只会访问向上的一行和左侧的一列,因此您实际需要的所有存储空间都是前一行和前一列,您可以以非常低的成本动态分配它们。这也会使其缩放到任意长度的字符串。

不过这需要仔细考虑一下!

关于go - goroutine 中的代码块产生奇怪的错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20368711/

相关文章:

go - 无论如何在ansi控制台上打印斜体字体?

go - 为什么不能同时为结构及其指针定义方法?

select - 跳出选择循环?

go - 如何通过遍历列表来创建多个 CRON 函数

multithreading - 为什么这段代码没有达到竞争条件?

go - 确保 goroutine 清理,最佳实践

go - metadata.FromOutgoingContext 和 metadata.FromIncomingContext 有什么区别?

go - Go标准库中是否有一个函数可以将缓冲区编码为go中的任何图像格式

c - 如何使用 GO 导入用 C 编写的 DLL 函数?

go - 为什么goroutines没有 `.join`操作?