我看到你的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