我正在尝试使用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
}
}
你对此有何建议?
答案 0 :(得分:1)
在第二种情况下,你确定goroutine是以“正确的顺序”执行的,因为你等到goroutines完成后再继续下一个。
一个例子是golang游乐场上的this minimal example。要解决此问题,您可能希望在渠道中传递三个成员的结构,即nx
,ny
和i
值。
答案 1 :(得分:0)
我怀疑你的“如果imData [ind] == e [i]”条件在前一种情况下失败了,但是如果没有通道的设置代码就很难分辨,并且更多关于那些不同切片的细节保持。您是否尝试使用print语句运行它以查看从频道获得的内容?
另请注意,如果相关频道已缓冲,则无法保证ch
和ch2
中的值的顺序相同。这很可能是你的问题。
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()
。对于此代码块,ch
,ch2
,arx
,ary
,dirf
和dirg
似乎都是有效的,因此不需要传递给go func()
。您只需要传入i
,因为循环在将机箱发射到goroutine后立即更改它。
现在,从纯粹的速度角度来看,你最好在go func()
调用中移动第一个循环。您可以在单个例程中触发,而不是在主例程中循环时创建7个goroutine,它将遍历值并在通道上发送它们。如果将通道缓冲到至少该大小,则这将成为非常快速的操作。顺便说一下,这也解决了频道排序的问题(尽管在单个频道上发送有序对作为结构仍然更好),因为你只有一个goroutine尝试发送频道。