2016-04-11 5 views
1

Ich habe den folgenden Code, den ich in ein paralleles Programm ändern soll.Julia Bild-Rendering durch Nebenläufigkeit ruiniert

// Stefan Nilsson 2013-02-27 

// This program creates pictures of Julia sets (en.wikipedia.org/wiki/Julia_set). 
package main 

import (
    "image" 
    "image/color" 
    "image/png" 
    "log" 
    "math/cmplx" 
    "os" 
    "strconv" 
) 

type ComplexFunc func(complex128) complex128 

var Funcs []ComplexFunc = []ComplexFunc{ 
    func(z complex128) complex128 { return z*z - 0.61803398875 }, 
    func(z complex128) complex128 { return z*z + complex(0, 1) }, 
} 

func main() { 
    for n, fn := range Funcs { 
     err := CreatePng("picture-"+strconv.Itoa(n)+".png", fn, 1024) 
     if err != nil { 
      log.Fatal(err) 
     } 
    } 
} 

// CreatePng creates a PNG picture file with a Julia image of size n x n. 
func CreatePng(filename string, f ComplexFunc, n int) (err error) { 
    file, err := os.Create(filename) 
    if err != nil { 
     return 
    } 
    defer file.Close() 
    err = png.Encode(file, Julia(f, n)) 
    return 
} 

// Julia returns an image of size n x n of the Julia set for f. 
func Julia(f ComplexFunc, n int) image.Image { 
    bounds := image.Rect(-n/2, -n/2, n/2, n/2) 
    img := image.NewRGBA(bounds) 
    s := float64(n/4) 
    for i := bounds.Min.X; i < bounds.Max.X; i++ { 
     for j := bounds.Min.Y; j < bounds.Max.Y; j++ { 
      n := Iterate(f, complex(float64(i)/s, float64(j)/s), 256) 
      r := uint8(0) 
      g := uint8(0) 
      b := uint8(n % 32 * 8) 
      img.Set(i, j, color.RGBA{r, g, b, 255}) 
     } 
    } 
    return img 
} 

// Iterate sets z_0 = z, and repeatedly computes z_n = f(z_{n-1}), n ≥ 1, 
// until |z_n| > 2 or n = max and returns this n. 
func Iterate(f ComplexFunc, z complex128, max int) (n int) { 
    for ; n < max; n++ { 
     if real(z)*real(z)+imag(z)*imag(z) > 4 { 
      break 
     } 
     z = f(z) 
    } 
    return 
} 

Ich habe beschlossen, die Julia() Funktion gleichzeitig zu versuchen und zu machen. Also habe ich es geändert in:

func Julia(f ComplexFunc, n int) image.Image { 
    bounds := image.Rect(-n/2, -n/2, n/2, n/2) 
    img := image.NewRGBA(bounds)     
    s := float64(n/4)       
    for i := bounds.Min.X; i < bounds.Max.X; i++ { 
     for j := bounds.Min.Y; j < bounds.Max.Y; j++ { 
      go func(){ 
       n := Iterate(f, complex(float64(i)/s, float64(j)/s), 256) 
       r := uint8(0) 
       g := uint8(0) 
       b := uint8(n % 32 * 8) 
       img.Set(i, j, color.RGBA{r, g, b, 255}) 
      }() 
     } 
    } 
    return img 

Diese Änderung bewirkt, dass die Bilder sehr unterschiedlich aussehen. Die Muster sind im Wesentlichen die gleichen, aber es gibt viele weiße Pixel, die vorher nicht da waren.

Was passiert hier?

Antwort

0

Es gibt zwei Probleme:

  1. Sie eigentlich nicht für Ihre goroutines warten zu beenden.
  2. Sie übergeben i and j nicht an die Goroutine, so dass sie fast immer die letzten i und j sein werden.

Ihre Funktion sollte etwas wie folgt aussehen:

func Julia(f ComplexFunc, n int) image.Image { 
    var wg sync.WaitGroup 
    bounds := image.Rect(-n/2, -n/2, n/2, n/2) 
    img := image.NewRGBA(bounds) 
    s := float64(n/4) 
    for i := bounds.Min.X; i < bounds.Max.X; i++ { 
     for j := bounds.Min.Y; j < bounds.Max.Y; j++ { 
      wg.Add(1) 
      go func(i, j int) { 
       n := Iterate(f, complex(float64(i)/s, float64(j)/s), 256) 
       r := uint8(0) 
       g := uint8(0) 
       b := uint8(n % 32 * 8) 
       img.Set(i, j, color.RGBA{r, g, b, 255}) 
       wg.Done() 
      }(i, j) 
     } 
    } 
    wg.Wait() 
    return img 
} 

Ein Bonus-Tipp, beim Tauchen in Gleichzeitigkeit, ist es normalerweise eine gute Idee, Ihren Code mit dem race detector zu versuchen.

Sie möglicherweise müssen einen Mutex img.Set anrufen, aber ich bin nicht sehr sicher, und ich kann nicht atm testen.

+0

Thx, arbeiten an einer Lösung ... :) – Sahand

+0

Mutex war nicht notwendig – Sahand