с использованием Array.Parallel.map для уменьшения времени выполнения

Привет всем

Я преобразовал проект на C # в F #, который рисует набор Мандельброта .
К сожалению, для рендеринга всего экрана требуется около минуты, поэтому я пытаюсь найти способы его ускорить.

Это один вызов, который занимает почти все время:

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

xyArray (double * double) [ ] => (массив кортежей типа double)
colorArray - это массив длиной int32 = 255

CalcZ определяется как:

 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

Поскольку я использую только половину мощности процессора, идея использования большего количества потоков и, в частности, Array.Parallel.map переводится как system.threading.tasks.parallel

Теперь мой вопрос

Наивное решение:

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

но это заняло вдвое больше времени, как я могу переписать это, чтобы это занимало меньше времени, или я могу взять какой-нибудь другой способ лучше использовать процессор?

Заранее спасибо
Gorgen

--- edit ---
функция, вызывающая 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)]

--- edit ---

После предложение от kvb (большое спасибо!) в комментарии к моему вопросу, я построил программу в режиме Release. Сборка в режиме Relase в целом ускорила работу.

Простое построение в Release заняло у меня от 50 до 30 секунд, перемещение всех преобразований в массиве, так что все это происходит за один проход, сделало это примерно на 10 секунд быстрее. Наконец, использование Array.Parallel.init дало мне чуть более 11 секунд.

Из этого я узнал ... Используйте режим релиза при хронометрировании и использовании параллельных конструкций ... Еще раз спасибо за помощь, которую я получил.
- edit -
с помощью ассемблера SSE из собственной библиотеки dll я смог сократить время с 12 до 1,2 секунды для полноэкранного режима. точек с наибольшей вычислительной нагрузкой. К сожалению, у меня нет графического процессора ...

Gorgen

5
задан Gorgen 26 June 2011 в 18:08
поделиться