我正在嘗試運行的程式是一個生成 1D 細胞自動化影像的生成器,它需要足夠強大以處理數百萬個單個細胞數量級的超大型模擬,因此需要多執行緒處理影像生成程序。我選擇 Go 是因為這個原因,因為 go-routines 將使 CPU 的作業分配問題變得更加容易和高效。現在因為用單獨的 go-routine 撰寫每個單元格的性能根本不會很高,我決定創建一個函式來呼叫影像物件并負責生成一整行單元格。此函式正在參考包含位切片的 2D 陣列物件(
現在,如果放大該影像,您會發現所有正方形都在垂直和水平方向上均勻分布,沒有例外。但是現在讓我們看一下并發輸出。

This version seems to have several anomalies many rows have been shrunk there are individual pixel errors in many places and although it follows the general pattern of the simulation correctly it is most certainly not visually pleasing. While i was investigating this issue i looked for issues related to concurrency and so i thought that perhaps a dynamic allocation of the pixel array in the image package might be causing conflicts of some sort and so i investigated img.Set() which looks like this...
func (p *NRGBA) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
i := p.PixOffset(x, y)
c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
s := p.Pix[i : i 4 : i 4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c1.R
s[1] = c1.G
s[2] = c1.B
s[3] = c1.A
}
However when i look at this it seems to make no sense. As it appears that img.Pix element is storing all the pixel data in a sequential 1D array of integers representing colors but the .Set() function immediately returns if the (x,y) elements passed to it are already found in the .Pix slice. But whats even more strange is what appears to be some sort of implicit assignment (which iv'e never seen in Go) where 4 elements of the .Pix slice are taken out representing an individual pixel's color and assigned to s. And the strangest part being that s, c1 and i are never referenced again, returned, or stored in memory simply thrown to garbage collection. But somehow this function appears to work sequentially so i just decided to let it do its thing and take a look at what the differences were in the .Pix slice between the concurrent and non concurrent implementations.
Now here's the links to four paste bins, they contain the img.Pix objects data for 2 separate trials arranged with each row belonging to an individual pixel's colors starting from the top left of each image and moving down. The reason for two trials is to verify consistency for the single threaded approach which appears to be consistent but as you can observe by going to a website like diffchecker.com is that both the multi threaded tests show differences between them and the single threaded output.
Multithreaded Test 1
Single-threaded Test 1
Multithreaded Test 2
Single-threaded Test 2
Now here I'll share some observations about this data.
- There are differences and different quantities of differences between the different multi-threaded and the single-threaded tests
- there are identical quantities of additions and deletions between single thread and multithread implying that all the data is present and that its simply in the wrong order.
Now these observations may imply that as we call the Set function threads are colliding with each other on certain indices in the Pix array but from looking at the set function every single pixel is supposed to have a distinct place in the array which is preallocated based on the length and width of the provided rectangle which should make ordering absolute and collisions impossible between threads. Heres the function thats responsible for creating the image object...
// NewRGBA returns a new RGBA image with the given bounds.
func NewRGBA(r Rectangle) *RGBA {
return &RGBA{
Pix: make([]uint8, pixelBufferLength(4, r, "RGBA")),
Stride: 4 * r.Dx(),
Rect: r,
}
}
So all in all I really have no idea whats going on. There seems to be some weird behaviors arising from the image package as multiple go-routines access the same slice but since the indices of the slice are theoretically absolute (meaning unique for each variable) there shouldn't be any ordering issues. The only possible issue i could think of is that the slice despite being defined in the manner it was is somehow being resized by that set function or at least shifted around causing collisions. Any help figuring out whats going wrong or any theories about what might be causing the problem are greatly appreciated. Cheers!
uj5u.com熱心網友回復:
上面的代碼產生了許多由于 go-routines 試圖寫入 .Pix 物件中的相同像素坐標而引起的競爭沖突。修復是在renderRow函式中,當前像素的寬度和高度的計算在每次迭代時重疊,<=而不是“<”。故事的寓意-race用于尋找沖突,并始終尋找對同一變數的覆寫或并發讀取。歸功于@rustyx。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/381126.html
