我看到你的conditionChecks
函数在每个false
值后递归。它看起来像你试图写下面的算法:
- 写一个函数为每个条件进行检查。
- 等待所有条件成为真实。 (保持重新检查任何错误的条件)。
- 继续执行事件循环。
在我看来,每个条件检查是某种async
表达式在这里将是一个很好的解决方案。 async
将继续运行,直到条件成立,然后完成并返回值true
。然后,您会收集列表中的异步,并同步运行异步的整个列表。奖励:如果条件允许他们的支票可以并行执行,这将为您节省时间。
let r = new System.Random()
let rec someCondition1() =
async {
// if r.Next() % 523452321 = 0 then
printfn "Checking condition 1"
if r.Next() % 52 = 0 then // So our output is shorter
return true
else
return! someCondition1()
}
let rec someCondition2() =
async {
// if r.Next() % 243142321 = 0 then
printfn "Checking condition 2"
if r.Next() % 24 = 0 then // So our output is shorter
return true
else
return! someCondition2()
}
let allConditions = [
someCondition1()
someCondition2()
]
let rec eventLoop() =
printfn "Event loop runs now"
// eventLoop() // Disabled so our test run will not infiloop
let ready = allConditions |> Async.Parallel |> Async.RunSynchronously
if Array.reduce (&&) ready then
eventLoop()
else
printfn "Some conditions returned false somehow"
运行这对我来说产生不同的结果,当然,但它们通常看起来是这样的:
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 2
Checking condition 2
Checking condition 1
Checking condition 2
Checking condition 1
Checking condition 2
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Event loop runs now
正如你所看到的,条件2设法在其第四次尝试返回true
,和停止 - 而条件1花了大约二十五次尝试才得到true
结果。但是,一旦所有结果都是true
,事件循环就会运行。
顺便说一句,我写这个的方式也允许在条件检查中“中止”。如果任何条件检查可以确定它会永不可以满足,它可能会返回false
,在这种情况下,事件循环将不会运行。所以:
let condition1CanNeverBeTrue() =
r.Next() % 123456789 = 0
let rec someCondition1() =
async {
if r.Next() % 523452321 = 0 then
return true
else
if condition1CanNeverBeTrue() then
return false
else
return! someCondition1()
}
您可能不需要这个额外的功能,但它可能派上用场。
而且,如果你不能并行运行的条件,但必须按顺序运行,然后更换let ready = ...
行:
let ready = allConditions |> List.map Async.RunSynchronously
,当然,使用List.reduce
代替Array.reduce
底。
请注意在异步表达式中使用'return'和'return!'。 'return'接受给定的值并将其包装在一个'Async <'T>'(这里是一个'Async'''''),而'return!'想要一个'Async <'T>'并且按原样传递它,因此''return !someCondition1()'最终是一个尾部调用,并且这段代码永远不会耗尽堆栈 –
rmunn
另外请注意,当我构建'allConditions'列表时,我实际调用了'someCondition'函数,这是因为它们的签名是'单元 - > Async'。调用它们实际上并不运行异步,它只是创建'Async '对象,它不会运行,直到它传递到'Async.RunSynchronously'(或'Async.Start'或一个其他方法在'Async'模块中告诉你他们实际运行异步计算 –
rmunn
r.Next()调用不是线程安全的;如果你想避免同步,每个条件需要到o自己的“随机”。 – ildjarn