f# - 生命游戏的递归函数不会在异步中运行

标签 f#

我正在尝试运行一个函数来更新用 f# 编写的生命游戏函数的网格,并且所有内容都必须是递归的,没有可变的。我想通过异步运行更新函数向表单添加一个暂停按钮,但是当我执行此操作时,仅更新一个方 block 。然而,当我在没有异步的情况下单步执行程序时,所有方 block 都会更新。有什么想法吗?

let buttonGrid : Button list list = (Startup ar);;

//transform buttongrid to int grid
let rec bg2ig (bg:Button list list) = 
    let rec innerLoop (bl:Button list) =
        match bl with
        |[] -> []
        |x::xs -> if (x.Name = "0") then 0::(innerLoop xs) else 1::(innerLoop xs)
    match bg with
    |[] -> []
    |y::ys -> (innerLoop y)::(bg2ig ys)

let Update (bg:Button list list)=
    let ar = (bg2ig bg)
    let rec innerUpdate (bg:Button list list)= 
        let rec arrayLoop (bl:Button list) y = 
            match bl with
            |[] -> 0
            |x::xs -> 
                let X = (15-xs.Length)
                let n = (neighbors X y ar)
                if  (ar.[X].[y] = 0) then (if n=3 then buttonGrid.[X].[y].Name<-"1") else (if (n=2||n=3)=false then buttonGrid.[X].[y].Name<-"0")
                if buttonGrid.[15-xs.Length].[y].Name="0" 
                then buttonGrid.[15-xs.Length].[y].BackColor <- Color.White 
                else buttonGrid.[15-xs.Length].[y].BackColor <- Color.Black
                arrayLoop xs y
        match bg with
        |[] -> []
        |y::ys -> 
            ignore (arrayLoop y (15-ys.Length)) 
            innerUpdate ys
    innerUpdate bg

let Running = async {
    let rec SubRun (x:int) =
        ignore (Update buttonGrid)
        if x = 1 then
            SubRun 1
        else
            0
    ignore (SubRun 1)
    do! Async.Sleep(1000)
    }

let RunAll() = 
    Running
    |> Async.RunSynchronously
    |> ignore

最佳答案

正如评论中提到的,对于这种情况,Async.RunSynchronously 是一个错误的函数。它在后台线程上启动工作流程(这是错误的,因为您想要访问 GUI 元素),然后它会阻塞调用线程,直到后台工作完成(这是错误的,因为您不想阻塞 GUI 线程)。

您需要使用Async.StartImmediate来启动当前线程(这将是GUI线程)上的工作而不阻塞。当工作流程的第一部分完成时(在 sleep 之前),GUI 线程可以自由地执行其他工作。 Sleep 之后,工作流程将再次在 GUI 线程上继续(这要归功于 StartImmediate 自动完成),因此您可以再次访问 GUI。

此外,执行实际循环的 SubRun 函数也需要是异步的 - 所以我希望循环的主要部分看起来像这样:

let Running = async {
    let rec SubRun (x:int) = 
        // Perform update and then sleep before recursive call
        ignore (Update buttonGrid)
        do! Async.Sleep(1000)
        if x = 1 then
            return! SubRun 1
        else
            return 0 }

    // Start the loop and asynchronously ignore the result
    SubRun 1 |> Async.Ignore

let RunAll() = 
    // Start the computation immediately on the current threada
    Running |> Async.StartImmediate

关于f# - 生命游戏的递归函数不会在异步中运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14095369/

相关文章:

带有重载提取器的 Scala 语言?

来自流阅读器的 F# 懒惰评估?

F# 无法捕获 DivideByZeroException

functional-programming - 函数式编程: How to model relationships?

asp.net-mvc - F# 类型或 ASP.NET MVC 的系统类型?

multithreading - F# MailboxProcessor 限制并行度

f# - 为什么这个定义返回一个函数?

F# ((*)2) 和 ((<<<)1) 行为不同

multithreading - F# 每秒生成一个新的异步请求

f# - 无法连接函数的结果