使用Go通道加速循环

时间:2016-06-07 15:15:13

标签: go concurrency channels

我正在尝试使用Go的并发来加速我的代码,

这就是我所拥有的:

            for i:=7; i>-1; i-- {
                go func (ch chan int32, ch2 chan int32, i int, arx int32, ary int32, dirf []int8, dirg []int8) {
                    nx := arx + int32(dirf[i])
                    ny := ary + int32(dirg[i])
                    ch <- nx
                    ch2 <- ny

                }(ch, ch2, i, arx,ary,dirf,dirg)

            }
            for i:=7; i>-1; i-- {
                nxx := <- ch
                nyx := <- ch2
                ind := nyx*w+nxx
                if imData[ind] == e[i]{
                    process[c]=nxx
                    process[c+1]=nyx
                    c+=2
                    matrix[ind]=1
                }
            }

运行之后,我没有得到我预期的矩阵切片,它充满了零。

但是如果我运行下面的代码,它就会像没有通道的代码一样给出矩阵切片,但它太慢了。

            for i:=7; i>-1; i-- {
                go func (ch chan int32, ch2 chan int32, i int, arx int32, ary int32, dirf []int8, dirg []int8) {
                    nx := arx + int32(dirf[i])
                    ny := ary + int32(dirg[i])
                    ch <- nx
                    ch2 <- ny

                }(ch, ch2, i, arx,ary,dirf,dirg)
                nxx := <- ch
                nyx := <- ch2
                ind := nyx*w+nxx
                if imData[ind] == e[i]{
                    process[c]=nxx
                    process[c+1]=nyx
                    c+=2
                    matrix[ind]=1
                }
            }

第一个出了什么问题?有任何想法吗?我是Go的新人。因此,当你提出建议时,请明确。

编辑: 我编辑了代码以使值按正确顺序排列,

type data struct {
    i int
    nx int32
    ny int32
}

           for i:=7; i>-1; i-- {
                go func (ch chan data, i int, arx int32, ary int32, dirf []int8, dirg []int8) {
                    nx := arx + int32(dirf[i])
                    ny := ary + int32(dirg[i])
                    ch <- data{i,nx,ny}

                }(ch, i, arx,ary,dirf,dirg)

            }
            for i:=7; i>-1; i-- {
                d := <- ch
                nxx := d.nx
                nyx := d.ny
                j := d.i
                ind := nyx*w+nxx
                if imData[ind] == e[j]{
                    process[c]=nxx
                    process[c+1]=nyx
                    c+=2
                    matrix[ind]=1
                }
            }

它现在有效,但它仍然太慢。

我正在尝试加快这个主要代码:

for i:=7; i>-1; i-- {
        nx := arx + int32(dirf[i])
        ny := ary + int32(dirg[i])
        ind := ny*w+nx
        if imData[ind] == e[i]{
            process[c]=nx
            process[c+1]=ny
            c+=2
            matrix[ind]=1
        }
    }

你对此有何建议?

2 个答案:

答案 0 :(得分:1)

在第二种情况下,你确定goroutine是以“正确的顺序”执行的,因为你等到goroutines完成后再继续下一个。

一个例子是golang游乐场上的this minimal example。要解决此问题,您可能希望在渠道中传递三个成员的结构,即nxnyi值。

答案 1 :(得分:0)

我怀疑你的“如果imData [ind] == e [i]”条件在前一种情况下失败了,但是如果没有通道的设置代码就很难分辨,并且更多关于那些不同切片的细节保持。您是否尝试使用print语句运行它以查看从频道获得的内容?

另请注意,如果相关频道已缓冲,则无法保证chch2中的值的顺序相同。这很可能是你的问题。

Goroutine 1可以在ch上设置一个值,但是Goroutine 2可以在Goroutine 1到达它之前在ch2上放置一个值。如果你有7个goroutines,很可能会在频道(或其他任意数量)上看到以下排序:

ch:1,2,3,4,5,6,7

ch2:1,3,4,5,6,7,2

如果它们没有缓冲,那么你的代码是不可能的,但它在技术上仍然不安全(编辑:实际上,它仍然不会与第二个循环中的i匹配)。如果数据是一组有序对,则应将每对作为结构发送到单个通道。

顺便提一下,如果预期变量会在该呼叫之外发生变化,您只需将变量传递给go func()。对于此代码块,chch2arxarydirfdirg似乎都是有效的,因此不需要传递给go func()。您只需要传入i,因为循环在将机箱发射到goroutine后立即更改它。

现在,从纯粹的速度角度来看,你最好在go func()调用中移动第一个循环。您可以在单个例程中触发,而不是在主例程中循环时创建7个goroutine,它将遍历值并在通道上发送它们。如果将通道缓冲到至少该大小,则这将成为非常快速的操作。顺便说一下,这也解决了频道排序的问题(尽管在单个频道上发送有序对作为结构仍然更好),因为你只有一个goroutine尝试发送频道。