Gor*_*gen 5 parallel-processing f#
我已经将C#中的项目转换为F#,绘制了Mandelbrot集.
不幸的是,渲染全屏需要大约一分钟,所以我试着找到一些方法来加快它.
几乎所有时间都是一个电话:
Array.map (fun x -> this.colorArray.[CalcZ x]) xyArray
Run Code Online (Sandbox Code Playgroud)
xyArray (double * double) [] =>(double的元组数组)
colorArray是int32 length = 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
Run Code Online (Sandbox Code Playgroud)
因为我只使用大约一半的处理器容量是使用更多线程的想法,特别是Array.Parallel.map,转换为system.threading.tasks.parallel
现在我的问题
一个天真的解决方案,将是:
Array.Parallel.map (fun x -> this.colorArray.[CalcZ x]) xyArray
Run Code Online (Sandbox Code Playgroud)
但这花费了两倍的时间,我怎样才能重写这个以减少时间,或者我可以采取其他方式更好地利用处理器?
在此先感谢
Gorgen
---编辑---
调用的函数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);
Run Code Online (Sandbox Code Playgroud)
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)]
Run Code Online (Sandbox Code Playgroud)
- -编辑 - -
根据kvb的建议(非常感谢!)在我的问题评论中,我在发布模式下构建了程序.在Relase模式下构建通常可以加快速度.
刚刚在Release中构建,从50s到30s左右,在阵列上的所有变换中移动所有这一切都发生在一次通过使得它快了大约10秒.最后使用Array.Parallel.init让我超过11秒.
我从中学到的是......在计时和使用并行结构时使用释放模式...再一次,感谢我收到的帮助.
--edit--
通过使用来自本机dll的SSE声明,我已经能够将时间从大约12秒缩短到1.2秒,以获得最大计算密集点的全屏.不幸的是我没有图形处理器......
Gorgen
顺便说一句,看起来您正在生成一个坐标数组,然后将其映射到一个结果数组。init如果您使用该函数而不是: ,则不需要创建坐标数组map:Array.Parallel.init 1000 (fun y -> Array.init 1000 (fun x -> this.colorArray.[CalcZ (x, y)]))
编辑:以下内容可能不准确:
您的问题可能是您调用一个小函数一百万次,导致调度开销压倒了您正在做的实际工作。您应该将数组划分为更大的块,以便每个单独的任务花费一毫秒左右的时间。您可以使用数组的数组,以便调用Array.Parallel.map外部数组和Array.map内部数组。这样,每个并行操作将针对整行像素而不是单个像素进行操作。