Windows服务中的TPL

时间:2015-04-09 01:40:39

标签: c# windows-services task-parallel-library

我需要在Windows服务中执行一些并行编写的任务。我正在使用VS2013,.NET 4.5,这个线程Basic design pattern for using TPL inside windows service for C#表明TPL是可行的方法。

以下是我的实施。我想知道是否有人能告诉我我是否做得正确!

public partial class FtpLink : ServiceBase
{
    private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    private readonly ManualResetEvent _runCompleteEvent = new ManualResetEvent(false);

    public FtpLink()
    {
        InitializeComponent();

        // Load configuration
        WebEnvironment.Instance.Initialise();
    }

    protected override void OnStart(string[] args)
    {
        Trace.TraceInformation("DatabaseToFtp is running");

        try
        {
            RunAsync(_cancellationTokenSource.Token).Wait();
        }
        finally
        {
            _runCompleteEvent.Set();
        }
    }

    protected override void OnStop()
    {
        Trace.TraceInformation("DatabaseToFtp is stopping");

        _cancellationTokenSource.Cancel();
        _runCompleteEvent.WaitOne();

        Trace.TraceInformation("DatabaseToFtp has stopped");
    }

    private async Task RunAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            Trace.TraceInformation("Working");

            // Do the actual work
            var tasks = new List<Task>
            {
                Task.Factory.StartNew(() => new Processor().ProcessMessageFiles(), cancellationToken),
                Task.Factory.StartNew(() => new Processor().ProcessFirmware(), cancellationToken)
            };

            Task.WaitAll(tasks.ToArray(), cancellationToken);

            // Delay the loop for a certain time
            await Task.Delay(WebEnvironment.Instance.DatabasePollInterval, cancellationToken);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我会做一些不同的事情:

  1. OnStart应该及时执行。通常的做法是将工作推迟到负责实际工作的后台线程。你实际上正在做那个,但通过调用Task.Wait来阻止该线程,这种方式使得卸载到后台线程无用,因为执行再次变得同步。
  2. 你正在使用sync over async anti-pattern,这应该是基本上避免的。让调用方法并行调用工作。
  3. 我认为您可能正在使用ManualResetEvent反过来。您将RunAsync方法包含在try-finally块中,但只是从WaitOne调用OnStop。我根本不确定你是否需要一个锁,它(似乎是你当前的代码)似乎没有并行调用这个代码。相反,您可以将Task返回的RunAsync存储在一个字段中,然后等待它完成。
  4. 您正在使用阻止版本WaitAll。相反,您可以使用异步版本Task.WhenAll,它可以异步等待。