坚持 Go 并发
Stuck with Go concurrency
我似乎不知道下一步该做什么。我的目标是使用图像包中的 SubImage 函数从原始图像创建一个包含所有子图像的数组。我能够在 imageSplit() 函数中分割图像并通过通道传递给 imageReceiver() 函数。
我实际上在函数 imageReceiver() 中接收数据,但我不知道如何在从 imageSplit() 函数接收到所有图像后附加到数组并使用它。
// Partitions Image
func Partition(src image.Image) []image.Image {
newImg := image.NewNRGBA64(src.Bounds())
r := newImg.Rect
dx, dy := r.Dx(), r.Dy()
// partitionNum
pNum := 3
// partition x
px, py := (dx / pNum), (dy / pNum)
imgChan := make(chan image.Image)
imgStorage := make([]image.Image, 0)
for i := 1; i < pNum; i++ {
for j := 1; j < pNum; j++ {
startX, startY := ((px * i) - px), ((py * j) - py)
endX, endY := (px * i), (py * j)
go imageSplit(imgChan, newImg, startX, startY, endX, endY)
go imageReceiver(imgChan)
}
}
return imgStorage
}
// Creates sub-images of img
func imageSplit(imgChan chan image.Image, img *image.NRGBA64, startX, startY, endX, endY int) {
r := image.Rect(startX, startY, endX, endY)
subImg := img.SubImage(r)
imgChan <- subImg
}
// Receive sub-image from channel
func imageReceiver(imgChan chan image.Image) {
img := <-imgChan
spew.Dump(img.Bounds())
}
我想创建一个 image.Image 的全局数组,但我不确定这是否是 "save" 所有子图像的正确方法。
我想这有点令人困惑的原因是因为这是我第一次在 Go 中使用并发。
感谢您的帮助:)
有几种方法可以做到这一点,但我想说你的基本问题是你的接收器不进行聚合,如果你改变它,它不会是线程安全的。
修改接收器以进行聚合的简单选择是在循环之前分配一个 Image
数组,并将指向它的指针传递给接收器方法,然后在读取渠道。但是你会有一堆不同的 goroutines 争夺同一个数组的访问权。所以真的,你不希望聚合是多线程的。如果是,则需要锁定机制才能写入集合。
相反,您想在循环后阻塞。最简单的方法就是将接收器的主体放在循环之后内联,例如;
imgs := []image.Image{}
img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
问题出在现实世界中,然后您的软件会阻塞在那条线上并且没有响应(无法死机或退出或任何其他方式)所以您通常会使用频道 select至少有 2 个 channels/cases,一个 Partition
的调用者在需要退出时可以用来杀死它的中止通道,以及从 imgChan
接收的 case。那看起来会更像这样;
imgs := []image.Image{}
select {
case img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
case _ := <-abortChan:
return MyCustomError();
}
这使得您的聚合不是并发的,只有产生结果的工作我个人认为是更好的设计。我也可以解释如何锁定您的接收器方法,但我相信您可以找到大量互斥量等示例。
我似乎不知道下一步该做什么。我的目标是使用图像包中的 SubImage 函数从原始图像创建一个包含所有子图像的数组。我能够在 imageSplit() 函数中分割图像并通过通道传递给 imageReceiver() 函数。
我实际上在函数 imageReceiver() 中接收数据,但我不知道如何在从 imageSplit() 函数接收到所有图像后附加到数组并使用它。
// Partitions Image
func Partition(src image.Image) []image.Image {
newImg := image.NewNRGBA64(src.Bounds())
r := newImg.Rect
dx, dy := r.Dx(), r.Dy()
// partitionNum
pNum := 3
// partition x
px, py := (dx / pNum), (dy / pNum)
imgChan := make(chan image.Image)
imgStorage := make([]image.Image, 0)
for i := 1; i < pNum; i++ {
for j := 1; j < pNum; j++ {
startX, startY := ((px * i) - px), ((py * j) - py)
endX, endY := (px * i), (py * j)
go imageSplit(imgChan, newImg, startX, startY, endX, endY)
go imageReceiver(imgChan)
}
}
return imgStorage
}
// Creates sub-images of img
func imageSplit(imgChan chan image.Image, img *image.NRGBA64, startX, startY, endX, endY int) {
r := image.Rect(startX, startY, endX, endY)
subImg := img.SubImage(r)
imgChan <- subImg
}
// Receive sub-image from channel
func imageReceiver(imgChan chan image.Image) {
img := <-imgChan
spew.Dump(img.Bounds())
}
我想创建一个 image.Image 的全局数组,但我不确定这是否是 "save" 所有子图像的正确方法。
我想这有点令人困惑的原因是因为这是我第一次在 Go 中使用并发。 感谢您的帮助:)
有几种方法可以做到这一点,但我想说你的基本问题是你的接收器不进行聚合,如果你改变它,它不会是线程安全的。
修改接收器以进行聚合的简单选择是在循环之前分配一个 Image
数组,并将指向它的指针传递给接收器方法,然后在读取渠道。但是你会有一堆不同的 goroutines 争夺同一个数组的访问权。所以真的,你不希望聚合是多线程的。如果是,则需要锁定机制才能写入集合。
相反,您想在循环后阻塞。最简单的方法就是将接收器的主体放在循环之后内联,例如;
imgs := []image.Image{}
img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
问题出在现实世界中,然后您的软件会阻塞在那条线上并且没有响应(无法死机或退出或任何其他方式)所以您通常会使用频道 select至少有 2 个 channels/cases,一个 Partition
的调用者在需要退出时可以用来杀死它的中止通道,以及从 imgChan
接收的 case。那看起来会更像这样;
imgs := []image.Image{}
select {
case img := <-imgChan
imgs = append(imgs, img)
spew.Dump(img.Bounds())
case _ := <-abortChan:
return MyCustomError();
}
这使得您的聚合不是并发的,只有产生结果的工作我个人认为是更好的设计。我也可以解释如何锁定您的接收器方法,但我相信您可以找到大量互斥量等示例。