Привет всем
Я преобразовал проект в 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.карта, переводится как 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 (спасибо большое!) Вкомментарий к моему вопросу, я построил программу в режиме выпуска.Сборка в режиме Relase обычно ускоряет процесс.
Простое встраивание в релиз заняло у меня от 50 до примерно 30 секунд, когда все преобразования в массиве выполнялись так, что все это происходит за один проход, и это на 10 секунд быстрее.Наконец использование Array.Parallel.init дало мне чуть более 11 секунд.
Из этого я узнал, что ... Используйте режим освобождения при синхронизации событий и использовании параллельных конструкций ... Еще раз, спасибо за помощь, которую я получил.
-edit -
с помощью SSE-ассемблера из нативной dll. Мне удалось сократить время с 12 секунд до 1,2 секунд для полного экрана наиболее интенсивных вычислительных точек.К сожалению, у меня нет графического процессора ...
Gorgen