f# - progressbar - Escribir un servicio de sondeo de Windows
backgroundworker wpf (1)
Podría sentir la tentación de escribir un bucle simple en un flujo de trabajo asincrónico. Puedes usar do! Async.Sleep interval
do! Async.Sleep interval
para dormir entre las encuestas - esto tiene dos ventajas: no estás atando un hilo solo para que permanezca inactivo con Thread.Sleep
, y the do!
verifica automáticamente la cancelación si pasa un CancellationToken
en Async.Start
.
Además, si su operación de sondeo implica comunicación de red, ya está en un flujo de trabajo asíncrono, por lo que es trivial realizar llamadas de red asincrónicas.
Normalmente escribo servicios de Windows en C #, pero le doy una oportunidad en F #. Para un servicio de votación, como este, normalmente utilizo una clase que he escrito, que es similar a BackgroundWorker
. Genera un hilo de fondo y dispara un método OnWork a intervalos regulares. (El código completo está aquí [github] ).
¿Hay alguna otra manera, quizás mejor o más idiomática, de hacer esto en F #? Podría ser una forma mejor de escribir la clase de trabajador de fondo de sondeo o las alternativas incorporadas a ella.
EDITAR
Esto es lo que surgió, basado en la sugerencia de Joel.
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()
El servicio que usa 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)
Ojalá hubiera una forma de evitar el CancellationTokenSource
mutable, pero por desgracia.