当前位置 : 主页 > 网络安全 > 测试自动化 >

F#代码性能可怕

来源:互联网 收集:自由互联 发布时间:2021-06-22
这是我的第一个F#计划.我以为我会把Conway的生命游戏作为第一个练习. 请帮助我理解为什么下面的代码有如此可怕的性能. let GetNeighbours (p : int, w : int, h : int) : seqint = let (f1, f2, f3, f4) =
这是我的第一个F#计划.我以为我会把Conway的生命游戏作为第一个练习.

请帮助我理解为什么下面的代码有如此可怕的性能.

let GetNeighbours (p : int, w : int, h : int) : seq<int> =
    let (f1, f2, f3, f4) = (p > w, p % w <> 1, p % w <> 0, p < w * (h - 1))
    [
    (p - w - 1, f1 && f2);
    (p - w, f1);
    (p - w + 1, f1 && f3);
    (p - 1, f2);
    (p + 1, f3);
    (p + w - 1, f4 && f2);
    (p + w, f4);
    (p + w + 1, f4 && f3)
    ]
    |> List.filter (fun (s, t) -> t)
    |> List.map (fun (s, t) -> s)
    |> Seq.cast

let rec Evolve (B : seq<int>, S : seq<int>, CC : seq<int>, g : int) : unit =
    let w = 10
    let h = 10
    let OutputStr = (sprintf "Generation %d:  %A" g CC) // LINE_MARKER_1
    printfn "%s" OutputStr
    let CCN = CC |> Seq.map (fun s -> (s, GetNeighbours (s, w, h)))
    let Survivors =
        CCN
        |> Seq.map (fun (s, t) -> (s, t |> Seq.map (fun u -> (CC |> Seq.exists (fun v -> u = v)))))
        |> Seq.map (fun (s, t) -> (s, t |> Seq.filter (fun u -> u)))
        |> Seq.map (fun (s, t) -> (s, Seq.length t))
        |> Seq.filter (fun (s, t) -> (S |> Seq.exists (fun u -> t = u)))
        |> Seq.map (fun (s, t) -> s)
    let NewBorns =
        CCN
        |> Seq.map (fun (s, t) -> t)
        |> Seq.concat
        |> Seq.filter (fun s -> not (CC |> Seq.exists (fun t -> t = s)))
        |> Seq.groupBy (fun s -> s)
        |> Seq.map (fun (s, t) -> (s, Seq.length t))
        |> Seq.filter (fun (s, t) -> B |> Seq.exists (fun u -> u = t))
        |> Seq.map (fun (s, t) -> s)
    let NC = Seq.append Survivors NewBorns
    let SWt = new System.Threading.SpinWait ()
    SWt.SpinOnce ()
    if System.Console.KeyAvailable then
        match (System.Console.ReadKey ()).Key with
        | System.ConsoleKey.Q -> ()
        | _ -> Evolve (B, S, NC, (g + 1))
    else 
        Evolve (B, S, NC, (g + 1))

let B = [3]
let S = [2; 3]
let IC = [4; 13; 14]
let g = 0
Evolve (B, S, IC, g)

前五次迭代,即第0代,第1代,第2代,第3代,4代,没有问题.然后,在大约100毫秒的短暂停顿之后,完成第5代.但在那之后,程序挂起标记为“LINE_MARKER_1”的行,正如断点Visual Studio所揭示的那样.它永远不会到达printfn线.

奇怪的是,已经是第2代,函数Evolve中的CC序列已经稳定到序列[4; 13; 14; 3]所以我认为没有理由为什么第6代不能进化.

我知道通常认为粘贴大段代码并在调试时请求帮助是不合适的,但我不知道如何将其减少到最小的工作示例.我们将非常感谢任何有助于我调试的指针.

在此先感谢您的帮助.

编辑

我真的相信任何希望帮助我的人都可能会忽略GetNeighbours功能.我把它包括在内是为了完整起见.

看到评论和所有,但这个代码运行像地狱 – 使用List.*和一些其他较小的优化:

let GetNeighbours p w h =
    let (f1, f2, f3, f4) = p > w, p % w <> 1, p % w <> 0, p < w * (h - 1)
    [
        p - w - 1, f1 && f2
        p - w, f1
        p - w + 1, f1 && f3
        p - 1, f2
        p + 1, f3
        p + w - 1, f4 && f2
        p + w, f4
        p + w + 1, f4 && f3
    ]
    |> List.choose (fun (s, t) -> if t then Some s else None)

let rec Evolve B S CC g =
    let w = 10
    let h = 10
    let OutputStr = sprintf "Generation %d:  %A" g CC // LINE_MARKER_1
    printfn "%s" OutputStr
    let CCN = CC |> List.map (fun s -> s, GetNeighbours s w h)
    let Survivors =
        CCN
        |> List.choose (fun (s, t) ->
            let t =
                t
                |> List.filter (fun u -> CC |> List.exists ((=) u))
                |> List.length
            if S |> List.exists ((=) t) then
                Some s
            else None)
    let NewBorns =
        CCN
        |> List.collect snd
        |> List.filter (not << fun s -> CC |> List.exists ((=) s))
        |> Seq.countBy id
        |> List.ofSeq
        |> List.choose (fun (s, t) ->
            if B |> List.exists ((=) t) then
                Some s
            else None)
    let NC = List.append Survivors NewBorns
    let SWt = new System.Threading.SpinWait()
    SWt.SpinOnce()
    if System.Console.KeyAvailable then
        match (System.Console.ReadKey()).Key with
        | System.ConsoleKey.Q -> ()
        | _ -> Evolve B S NC (g + 1)
    else 
        Evolve B S NC (g + 1)

let B = [3]
let S = [2; 3]
let IC = [4; 13; 14]
let g = 0
Evolve B S IC g
网友评论