如何使用异步编写具有长期运行功能的Windows服务?

时间:2019-01-26 13:30:27

标签: c# .net windows service

我的第一个非异步尝试是使用计时器每15秒调用一次该进程。这样很快就创建了多个运行的进程,这些启动了数据库上的争用条件,因为根据队列的大小,函数_myApp.ProcessQueue();可能需要5到10分钟才能运行。这实际上锁定了数据库,因为它试图读取和写入相同的行。如果我增加计时器,可以防止发生竞争状况的可能性,但是我认为这不是一种非常实用的服务方式。

protected override void OnStart(string[] args)
{
    _log.Info($"Service is started at {DateTime.Now}.");
    timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
    timer.Interval = 15000;
    timer.Enabled = true;
}

private void OnElapsedTime(object source, ElapsedEventArgs e)
{
    int recCount = _dbHandler.CheckQueueCount();

    if (recCount > 0)
    {
        _log.Info($"Found {recCount} records in the queue.");

        try
        {
            _myApp.ProcessQueue();
        }
        catch (Exception exception)
        {
            _log.Error(exception);                    
            Stop();
        }
    }
}

我正在考虑解决此问题的方法是使用异步函数,但是由于以前从未使用过.Net的异步功能,因此我很难编写它。

1 个答案:

答案 0 :(得分:0)

使用OnStart()在另一个线程(Task.Run()或如果必须调整某些参数Task.Factory.Start())中初始化运行器,以在短时间内正确返回该方法。

如果我对您的理解正确,那么您一次只想处理一项工作,然后再处理下一项,对吗?

我的示例包括始终等待额外的15秒。如果您不希望这样做,则必须稍微调整一下代码。

没有异步/等待状态

要使循环与作业处理同步,可以在另一个线程中启动作业(请参见上文),并使用AutoResetEvent。在您的循环中,您将等待_autoResetEvent.WaitOne(),一旦完成工作,您就可以用_autoResetEvent.Set()发出信号通知另一个线程继续执行。

使用合适的东西来等待15秒钟,例如Thread.Sleep()

使用异步/等待 这要容易得多,您只需要等待任务调用即可。

await Task.Run(() => MyJobMethod(argA, argB, ...));
await Task.Delay(15000);