Golang을 사용한 병렬 만델브로 집합
35535 단어 performanceprogramminggo
goroutines
을 사용하여 Mandelbrot 세트를 병렬로 생성하는 방법을 설명합니다.여기 소스 코드: https://github.com/GiselaMD/parallel-mandelbrot-go
만델브로 집합
Mandelbrot 집합이 무엇인지에 관심이 있는 사람들은 확인하십시오https://en.wikipedia.org/wiki/Mandelbrot_set.
설정된 수식은
x
및 y
좌표의 위치를 기반으로 합니다.x = x*x - y*y + a
y = 2*x*y + b
색상을 설정하기 위해
x*x + y*y > 4
여부도 확인합니다.그러나 수학 세부 사항으로 들어가는 대신 화면에 Mandelbrot 세트를 렌더링하기 위해
gourotines
를 사용할 수 있는 방법을 설명하고 싶습니다.코드에 들어가기
이 프로그램은 Mandelbrot 집합의 성능과 해상도에 영향을 미칠 4가지 주요 값을 기반으로 합니다.
maxIter = 1000
samples = 200
numBlocks = 64
numThreads = 16
maxIter
는 mandelbrot 공식이 계산되는 횟수를 정의하여 x
및 y
값을 생성합니다. samples
는 RGB 색상 값을 생성하는 상호 작용의 수입니다. numBlocks
는 이미지를 몇 조각으로 나눌 것인지에 있습니다. numThreads
는 생성될 gourotines
의 수입니다. 결과를 화면에 렌더링하기 위해 Pixel 라이브러리(github.com/faiface/pixel)를 사용했습니다. main 함수에는 다음과 같은 것이 있습니다.
func main() {
pixelgl.Run(run)
}
pixelgl.Run을 호출하면 PixelGL이 기본 기능을 제어하게 되며 더 이상 기본 기능에서 코드를 실행할 방법이 없습니다. 그렇기 때문에 pixelgl.Run 내부에
run
함수인 또 다른 함수를 전달해야 합니다.func run() {
log.Println("Initial processing...")
pixelCount = 0
img = image.NewRGBA(image.Rect(0, 0, imgWidth, imgHeight))
cfg := pixelgl.WindowConfig{
Title: "Parallel Mandelbrot in Go",
Bounds: pixel.R(0, 0, imgWidth, imgHeight),
VSync: true,
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
log.Println("Rendering...")
start := time.Now()
workBuffer := make(chan WorkItem, numBlocks)
threadBuffer := make(chan bool, numThreads)
drawBuffer := make(chan Pix, pixelTotal)
workBufferInit(workBuffer)
go workersInit(drawBuffer, workBuffer, threadBuffer)
go drawThread(drawBuffer, win)
for !win.Closed() {
pic := pixel.PictureDataFromImage(img)
sprite := pixel.NewSprite(pic, pic.Bounds())
sprite.Draw(win, pixel.IM.Moved(win.Bounds().Center()))
win.Update()
if showProgress {
fmt.Printf("\r%d/%d (%d%%)", pixelCount, pixelTotal, int(100*(float64(pixelCount)/float64(pixelTotal))))
}
if pixelCount == pixelTotal {
end := time.Now()
fmt.Println("\nFinished with time = ", end.Sub(start))
pixelCount++
if closeOnEnd {
break
}
}
}
}
run
함수는 창을 초기화 및 업데이트하고 gourotines
에 사용할 채널을 만드는 역할을 합니다.workBuffer
는 (numBlocks
를 기준으로) 각 블록의 정보를 추가하는 역할을 하는 채널입니다. workBufferInit
내부에서 초기 및 최종 x
및 y
값이 채널로 전송되어 작업할 이미지 조각을 가져오는 각 gourotines
가 전역 데이터를 알 필요 없이 색상을 계산할 수 있습니다. , 해당 블록의 x
및 y
범위만 해당됩니다.func workBufferInit(workBuffer chan WorkItem) {
var sqrt = int(math.Sqrt(numBlocks))
for i := sqrt - 1; i >= 0; i-- {
for j := 0; j < sqrt; j++ {
workBuffer <- WorkItem{
initialX: i * (imgWidth / sqrt),
finalX: (i + 1) * (imgWidth / sqrt),
initialY: j * (imgHeight / sqrt),
finalY: (j + 1) * (imgHeight / sqrt),
}
}
}
}
threadBuffer
는 goroutines
를 기반으로 numThreads
를 생성하고 goroutine
가 작업을 완료하는 시기를 제어하여 다른 작업을 대신 실행할 수 있도록 합니다. 그 논리는 workersInit
goroutine
.func workersInit(drawBuffer chan Pix, workBuffer chan WorkItem, threadBuffer chan bool) {
for i := 1; i <= numThreads; i++ {
threadBuffer <- true
}
for range threadBuffer {
workItem := <-workBuffer
go workerThread(workItem, drawBuffer, threadBuffer)
}
}
workItem
(각 블록)에서 수신한 각 workBuffer
에 대해 모든 Mandelbrot 집합 논리를 처리하기 위해 goroutine
라는 workerThread
를 생성합니다.func workerThread(workItem WorkItem, drawBuffer chan Pix, threadBuffer chan bool) {
for x := workItem.initialX; x < workItem.finalX; x++ {
for y := workItem.initialY; y < workItem.finalY; y++ {
var colorR, colorG, colorB int
for k := 0; k < samples; k++ {
a := height*ratio*((float64(x)+RandFloat64())/float64(imgWidth)) + posX
b := height*((float64(y)+RandFloat64())/float64(imgHeight)) + posY
c := pixelColor(mandelbrotIteraction(a, b, maxIter))
colorR += int(c.R)
colorG += int(c.G)
colorB += int(c.B)
}
var cr, cg, cb uint8
cr = uint8(float64(colorR) / float64(samples))
cg = uint8(float64(colorG) / float64(samples))
cb = uint8(float64(colorB) / float64(samples))
drawBuffer <- Pix{
x, y, cr, cg, cb,
}
}
}
threadBuffer <- true
}
func mandelbrotIteraction(a, b float64, maxIter int) (float64, int) {
var x, y, xx, yy, xy float64
for i := 0; i < maxIter; i++ {
xx, yy, xy = x*x, y*y, x*y
if xx+yy > 4 {
return xx + yy, i
}
// xn+1 = x^2 - y^2 + a
x = xx - yy + a
// yn+1 = 2xy + b
y = 2*xy + b
}
return xx + yy, maxIter
}
func pixelColor(r float64, iter int) color.RGBA {
insideSet := color.RGBA{R: 0, G: 0, B: 0, A: 255}
// check if it's inside the set
if r > 4 {
// return hslToRGB(float64(0.70)-float64(iter)/3500*r, 1, 0.5)
return hslToRGB(float64(iter)/100*r, 1, 0.5)
}
return insideSet
}
drawBuffer
는 Mandelbrot 집합을 계산하는 goroutines
에서 값을 수신하는 채널이며 데이터를 수신하면 drawThread
goroutine
가 픽셀 RGB 값을 이미지에 설정한 다음 run
함수 창을 업데이트합니다.func drawThread(drawBuffer chan Pix, win *pixelgl.Window) {
for i := range drawBuffer {
img.SetRGBA(i.x, i.y, color.RGBA{R: i.cr, G: i.cg, B: i.cb, A: 255})
pixelCount++
}
}
또한 임의의 데이터를 생성하고 hsl 및 색상을 RGB로 변환하기 위한 몇 가지 utils 함수가 있습니다.
var randState = uint64(time.Now().UnixNano())
func RandUint64() uint64 {
randState = ((randState ^ (randState << 13)) ^ (randState >> 7)) ^ (randState << 17)
return randState
}
func RandFloat64() float64 {
return float64(RandUint64() / 2) / (1 << 63)
}
func hueToRGB(p, q, t float64) float64 {
if t < 0 { t += 1 }
if t > 1 { t -= 1 }
switch {
case t < 1.0 / 6.0:
return p + (q - p) * 6 * t
case t < 1.0 / 2.0:
return q
case t < 2.0 / 3.0:
return p + (q - p) * (2.0 / 3.0 - t) * 6
default:
return p
}
}
func hslToRGB(h, s, l float64) color.RGBA {
var r, g, b float64
if s == 0 {
r, g, b = l, l, l
} else {
var q, p float64
if l < 0.5 {
q = l * (1 + s)
} else {
q = l + s - l * s
}
p = 2 * l - q
r = hueToRGB(p, q, h + 1.0 / 3.0)
g = hueToRGB(p, q, h)
b = hueToRGB(p, q, h - 1.0 / 3.0)
}
return color.RGBA{ R: uint8(r * 255), G: uint8(g * 255), B: uint8(b * 255), A: 255 }
}
최종 결과:
오늘은 여기까지입니다!
즐기시기 바랍니다 😊
🇧🇷 이 게시물은 이 프로젝트에 협력한 다니엘이 게시한 포르투갈어로도 볼 수 있습니다. 게시물 확인: https://danielferreiradev.medium.com/fractal-de-mandelbrot-paralelo-usando-golang-4ba497d9bbc5
여기 소스 코드: https://github.com/GiselaMD/parallel-mandelbrot-go
Reference
이 문제에 관하여(Golang을 사용한 병렬 만델브로 집합), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/giselamd/parallel-mandelbrot-set-in-go-480o텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)