我需要在我正在并行编写的 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);
}
}
}
最佳答案
我会做一些不同的事情:
OnStart
应及时执行。常见的做法是将工作推迟到负责执行实际工作的后台线程。您实际上正在这样做,但是通过调用 Task.Wait 来阻塞该线程,这使得卸载到后台线程变得无用,因为执行再次变为同步。- 您正在使用sync over async anti-pattern ,这应该尽量避免。让调用方法并行调用工作。
- 我认为您可能会以相反的方式使用
ManualResetEvent
。您将RunAsync
方法包装在try-finally
block 中,但仅从OnStop
调用WaitOne
>。我不太确定您是否需要锁,(从您当前的代码来看)似乎没有并行调用此代码。相反,您可以将RunAsync
返回的Task
存储在字段中并等待其完成。 - 您正在使用阻塞版本
WaitAll
。相反,您可以使用异步版本Task.WhenAll
,它可以异步等待。
关于c# - Windows 服务内的 TPL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29528302/