Using Array.Parallel.map to reduce runtime

Hello everybody

I converted the project in C # to F #, which draws a Mandelbrot set.
Unfortunately, it takes about one minute to display a full screen, so I'm trying to find ways to speed it up.

This is one call that takes up most of the time:

Array.map (fun x -> this.colorArray.[CalcZ x]) xyArray

xyArray (double * double) []=> (binary array array)
colorArray - array of int32 length = 255

CalcZ defined as:

 let CalcZ (coord:double * double) =

    let maxIterations = 255

    let rec CalcZHelper (xCoord:double) (yCoord:double) // line break inserted
           (x:double) (y:double) iters =
        let newx = x * x + xCoord - y * y
        let newy = 2.0 * x * y + yCoord
        match newx, newy, iters with
        | _ when Math.Abs newx > 2.0 -> iters
        | _ when Math.Abs newy > 2.0 -> iters
        | _ when iters = maxIterations -> iters
        | _ -> CalcZHelper xCoord yCoord newx newy (iters + 1)

    CalcZHelper (fst coord) (snd coord) (fst coord) (snd coord) 0

Since I use only half the processor capacity, it is an idea to use more threads and, in particular, Array.Parallel.map, translates to system.threading.tasks.parallel

Now my question

Naive solution:

Array.Parallel.map (fun x -> this.colorArray.[CalcZ x]) xyArray  

, , , ?

--- ---
, CalcZ, :

          let GetMatrix =
            let halfX = double bitmap.PixelWidth * scale / 2.0
            let halfY = double bitmap.PixelHeight * scale / 2.0
            let rect:Mandelbrot.Rectangle = 
                {xMax = centerX + halfX; xMin = centerX - halfX;
                 yMax = centerY + halfY; yMin = centerY - halfY;}

            let size:Mandelbrot.Size = 
                {x = bitmap.PixelWidth; y = bitmap.PixelHeight}

            let xyList = GenerateXYTuple rect size
            let xyArray = Array.ofList xyList
            Array.map (fun x -> this.colorArray.[CalcZ x]) xyArray

        let region:Int32Rect = new Int32Rect(0,0,bitmap.PixelWidth,bitmap.PixelHeight)
        bitmap.WritePixels(region, GetMatrix, bitmap.PixelWidth * 4, region.X, region.Y);

GenerateXYTuple:

let GenerateXYTuple (rect:Rectangle) (pixels:Size) =
    let xStep = (rect.xMax - rect.xMin)/double pixels.x
    let yStep = (rect.yMax - rect.yMin)/double pixels.y
    [for column in 0..pixels.y - 1 do
       for row in 0..pixels.x - 1 do
         yield (rect.xMin + xStep * double row,
           rect.yMax - yStep * double column)]

--- ---

kvb ( !) , Release. Relase .

50 30 , , , 10 . , Array.Parallel.init, 11 .

, , - ... ... , , .
- -
SSE- DLL, 12 1,2 . , ...

Gorgen

+5
3

, , , . , init map: Array.Parallel.init 1000 (fun y -> Array.init 1000 (fun x -> this.colorArray.[CalcZ (x, y)]))

: : , , , . , . , Array.Parallel.map Array.map . , .

+1

, , . . .

, : http://pastebin.com/Rjj8EzCA

, , , .

+3

, Array.Parallel.map ( Parallel.For .NET 4.0 ) , ~ 1 . , , F # ( ).

I will try to take a copy of the function Parallel.mapfrom F # sources and add inline. Try adding the following function to your code mapand use it instead of the F # library:

let inline map (f: 'T -> 'U) (array : 'T[]) : 'U[]=
  let inputLength = array.Length
  let result = Array.zeroCreate inputLength
  Parallel.For(0, inputLength, fun i ->
    result.[i] <- f array.[i]) |> ignore
  result
+1
source

All Articles