Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 使用Array.Parallel.map减少运行时间 大家好_F#_Parallel Processing - Fatal编程技术网

F# 使用Array.Parallel.map减少运行时间 大家好

F# 使用Array.Parallel.map减少运行时间 大家好,f#,parallel-processing,F#,Parallel Processing,我已将一个C语言的项目转换为F语言,用于绘制Mandelbrot集。 不幸的是,它需要大约一分钟来呈现一个全屏,所以我试图找到一些方法来加快它 这是一个几乎占用所有时间的电话: Array.map (fun x -> this.colorArray.[CalcZ x]) xyArray xyArray(double*double)[=>(双元组数组) colorArray是长度为int32=255的数组 CalcZ定义为: let CalcZ (coord:double * doubl

我已将一个C语言的项目转换为F语言,用于绘制Mandelbrot集。
不幸的是,它需要大约一分钟来呈现一个全屏,所以我试图找到一些方法来加快它

这是一个几乎占用所有时间的电话:

Array.map (fun x -> this.colorArray.[CalcZ x]) xyArray
xyArray(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

现在我的问题

一个简单的解决方案是:

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的建议(非常感谢!)在对我的问题的评论中,我以发布模式构建了这个程序。在放松模式下的建筑通常会加快速度

刚发布的building就把我从50秒带到了30秒左右,在阵列上进行了所有的变换,所以这一切都发生在一个过程中,使它快了10秒左右。最后,使用Array.Parallel.init使我的时间刚好超过11秒

我从中学到的是。。。。在计时和使用并行构造时使用释放模式。。。 再一次感谢您对我的帮助。
--编辑--
通过使用本机dll中的SSE assember,我能够将计算最密集点的全屏显示时间从大约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
。这样,每个并行操作将在整行像素上运行,而不仅仅是一个像素。

我不认为
Array.parallel.map
函数(在封面下使用.NET 4.0中的
parallel.For
函数)在并行化操作时会遇到问题,如果它运行一个简单的函数~100万次。然而,在类似的情况下,当F#没有优化lambda函数的调用(以某种方式)时,我遇到了一些奇怪的性能行为

我会尝试从F#sources中复制一个
Parallel.map
函数,然后添加
inline
。尝试将以下
map
函数添加到您的代码中,并使用它而不是F#库中的函数:

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
让内联映射(f:'T->'U)(数组:'T[]):'U[]=
让inputLength=array.Length
让结果=Array.zeroCreate inputLength
并行。对于(0,输入长度,乐趣i->
结果。[i]忽略
结果

根据原始帖子上的评论,以下是我为测试该功能而编写的代码。快速版本在我的普通工作站上只需几秒钟。它是完全顺序的,没有并行代码

它的长度适中,因此我将其发布在另一个网站上:


我怀疑您看到的速度减慢是在呈现代码中。

所以它试图让每个函数调用都成为自己的任务?我想象过,但我在MSDN上找不到任何相关内容。我将研究init函数,感谢您提供的提示。@Gorgen:这不应该是一个真正的问题。它可能是)最好有数千次迭代,而不是数百万次(听起来很合理),但在我做的一些测试中,没有任何明显的差异。但当然,在编写并行代码时,重要的建议是自己测量它……托马斯:你可能是对的。我想的是ForEach而不是ForEach;我不确定的
是如何工作的。不管怎样,我相信我的建议是好主意。明天我会仔细看一看,当我写这篇文章时,我有我的妻子在背后支持我。。。是的,这确实是一个家庭项目:)我已经尝试了你的函数,但由于某种原因,它被我有一个数组(double*double)的事实窒息了至少我将错误消息解释为:“c->”d与类型seq不兼容我编写了一些代码,用你的函数提供的数据生成一个图像,生成1920x1200灰度图像只需几秒钟。您确定问题不是您的渲染代码吗?(再说一遍,FSI似乎确实以某种方式使事情运行得比正常情况更快…)运行代码时,在1920x1200,没有绘图的情况下,我得到了平均超过20次的运行,非并行版本为452ms,并行版本为135ms,这在我的4核Windows 7虚拟机上是大约3.4的加速。在mono 2.8上运行在我的Ubuntu盒上的相同代码的非并行时间为743ms,并行版本的噪声时间从35ms到992ms不等。使用System.Diagnostics.Stopwatch测量所有时间。你是否平均多次跑步得出结论?你有机会使用mono吗?@Jason:没有,我坐在一个有1GB内存和两个内核的电子书上。为了测量,我测量了断点之间的时间,我使用了VS2010Shell和F#@Jason:我测量了非并行,pa