2016-04-11 2 views
1

У меня есть следующий код, который я должен изменить в параллельную программу.Джулия установил рендеринг изображения, разрушенный параллелизмом

// 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 
} 

Я решил попробовать и сделать Julia() функции совпадают. Поэтому я изменил его на:

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 

Это изменение приводит к тому, что изображения выглядят совсем по-другому. Шаблоны по существу одинаковы, но есть много белых пикселей, которых раньше не было.

Что здесь происходит?

ответ

0

Есть 2 проблемы:

  1. Вы на самом деле не ждать ваших goroutines до конца.
  2. Вы не пропускаете i and j в goroutine, поэтому они почти всегда будут последними i и j.

Ваша функция должна выглядеть примерно так:

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 
} 

бонус наконечник, при погружении в параллельности, обычно это хорошая идея, чтобы попробовать ваш код с race detector.

Вы можете использовать мьютексы для звонка img.Set, но я не очень уверен, и я не могу проверить атм.

+0

Thx, работающий над решением ... :) – Sahand

+0

мьютекс не нужен – Sahand

Смежные вопросы