我通常在C#中编写Windows服务,但我在F#中使用它。对于像这样的轮询服务,我通常使用我写的类,类似于BackgroundWorker
。它会生成一个后台线程并定期触发 OnWork 方法。 (完整代码为here [github]。)
在F#中有另一种,或许更好或更惯用的方法吗?这可能是编写轮询后台工作者类或更好的内置替代方法的更好方法。
根据乔尔的建议,这就是我提出来的。
module Async =
open System.Diagnostics
let poll interval work =
let sw = Stopwatch()
let rec loop() =
async {
sw.Restart()
work()
sw.Stop()
let elapsed = int sw.ElapsedMilliseconds
if elapsed < interval then
do! Async.Sleep(interval - elapsed)
return! loop()
}
loop()
//Example
open System.Threading
let cts = new CancellationTokenSource()
Async.Start(Async.poll 2000 (fun () -> printfn "%A" DateTime.Now), cts.Token)
Thread.Sleep(TimeSpan.FromSeconds(10.0))
cts.Cancel()
使用poll
的服务:
type MyService() =
inherit System.ServiceProcess.ServiceBase()
let mutable cts = new CancellationTokenSource()
let interval = 2000
override __.OnStart(_) =
let polling = Async.poll interval (fun () ->
//do work
)
Async.Start(polling, cts.Token)
override __.OnStop() =
cts.Cancel()
cts.Dispose()
cts <- new CancellationTokenSource()
override __.Dispose(disposing) =
if disposing then cts.Dispose()
base.Dispose(true)
我希望有办法避免变异CancellationTokenSource
,但唉。
答案 0 :(得分:5)
我可能想在异步工作流中编写一个简单的循环。您可以使用do! Async.Sleep interval
在轮询之间进入睡眠状态 - 这有两个好处:您不是为了让它与Thread.Sleep
闲置而绑定线程,而do!
会自动检查如果您将CancellationToken
传递给Async.Start
,则会取消。
另外,如果您的轮询操作涉及网络通信,那么您已经处于异步工作流程中,这使得进行异步网络呼叫变得微不足道。