【问题标题】:Writing a polling Windows service编写轮询 Windows 服务
【发布时间】:2011-09-24 05:10:36
【问题描述】:

我通常使用 C# 编写 Windows 服务,但我尝试使用 F#。对于像这样的轮询服务,我通常使用自己编写的类,类似于BackgroundWorker。它产生一个后台线程并定期触发一个 OnWork 方法。 (完整代码为here [github]。)

在 F# 中是否有另一种可能更好或更惯用的方法来做到这一点?这可能是编写轮询后台工作者类或内置替代方案的更好方法。

编辑

这是我根据 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()

服务使用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,但是唉。

【问题讨论】:

  • 在相关说明中,有人创建了 F# 服务模板。它可能包含一些好的样板代码,但它不包含任何关于轮询的内容。 visualstudiogallery.msdn.microsoft.com/…
  • 我看到了。谢谢。我希望我知道如何发布对它的一些改进建议。
  • +1 用您的解决方案更新您的问题。

标签: f# windows-services backgroundworker


【解决方案1】:

我可能很想在异步工作流中编写一个简单的循环。您可以使用do! Async.Sleep interval 在轮询之间休眠 - 这有两个优点:您不会为了让线程与Thread.Sleep 闲置而占用线程,如果您通过,do! 会自动为您检查取消将CancellationToken 转换为Async.Start。

另外,如果您的轮询操作涉及网络通信,那么您已经处于异步工作流程中,因此进行异步网络调用变得微不足道。

【讨论】:

  • 我一直在思考这些问题,但不确定如何发送启动/停止信号(它需要可重新启动)。 MailboxProcessor 会产生一个好的解决方案吗?
  • 好吧,如果您的循环处于异步工作流程中,您可以创建一个CancellationTokenSource 并使用Async.Start(myLoop, cts.Token) 启动工作流程。要停止,请致电cts.Cancel()。要重新启动,请以与第一次相同的方式再次启动工作流...
  • 乔尔的建议可能会奏效;或者,您可以显式(或通过控制流隐式)表示 MailboxProcessor 中的状态机。如果您想强调状态和转换,那么我想我会使用 MailboxProcessor 和显式状态;如果你想强调这项工作,并且让状态/转换只是服务必要性的一部分,我可能只使用带有Start/Cancel 的异步循环。但我猜测,不是基于该领域的经验。
  • 我根据您的回答用我的解决方案更新了我的问题。似乎工作得很好。非常感谢。
  • @Brian:我倾向于MailboxProcessor,但我认为在这种情况下我关心的唯一转换是停止/启动,async+CancellationToken 处理得很好。
猜你喜欢
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
  • 2017-05-18
  • 2011-05-31
  • 1970-01-01
  • 2011-08-24
相关资源
最近更新 更多