DrG*_*iff 8 c# parallel-processing windows-services task-parallel-library async-await
简单来说
我有一个Windows服务,并行执行多个作业作为异步任务.然而,当调用OnStop时,似乎这些都立即被终止而不是被允许以更加亲切的方式停止.
更详细
每个工作代表一次工作的迭代,因此完成工作后,工作需要再次运行.
为实现这一目标,我正在编写一个概念验证Windows服务:
当我运行服务时,我看到所有内容都按预期执行.但是,当我停止服务时,似乎一切都停止了.
好的 - 那这是怎么回事?
在服务中,我有一个取消令牌和一个TaskCompletion Source:
private static CancellationTokenSource _cancelSource = new CancellationTokenSource();
private TaskCompletionSource<bool> _jobCompletion = new TaskCompletionSource<bool>();
private Task<bool> AllJobsCompleted { get { return _finalItems.Task; } }
Run Code Online (Sandbox Code Playgroud)
这个想法是,当每个Job优雅地停止时,Task AllJobsCompleted将被标记为已完成.
OnStart只是开始运行这些作业:
protected override async void OnStart(string[] args)
{
_cancelSource = new CancellationTokenSource();
var jobsToRun = GetJobsToRun(); // details of jobs not relevant
Task.Run(() => this.RunJobs(jobsToRun, _cancelSource.Token).ConfigureAwait(false), _cancelSource.Token);
}
Run Code Online (Sandbox Code Playgroud)
Task RunJobs将以并行循环运行每个作业:
private async Task RunModules(IEnumerable<Jobs> jobs, CancellationToken cancellationToken)
{
var parallelOptions = new ParallelOptions { CancellationToken = cancellationToken };
int jobsRunningCount = jobs.Count();
object lockObject = new object();
Parallel.ForEach(jobs, parallelOptions, async (job, loopState) =>
{
try
{
do
{
await job.DoWork().ConfigureAwait(false); // could take 5 seconds
parallelOptions.CancellationToken.ThrowIfCancellationRequested();
}while(true);
}
catch(OperationCanceledException)
{
lock (lockObject) { jobsRunningCount --; }
}
});
do
{
await Task.Delay(TimeSpan.FromSeconds(5));
} while (modulesRunningCount > 0);
_jobCompletion.SetResult(true);
}
Run Code Online (Sandbox Code Playgroud)
因此,应该发生的事情是,当每个作业完成当前迭代时,应该看到取消已经发出信号,然后应该退出循环并递减计数器.
然后,当jobsRunningCount达到零时,我们更新TaskCompletionSource.(可能有一种更优雅的方式来实现这一目标......)
因此,对于OnStop:
protected override async void OnStop()
{
this.RequestAdditionalTime(100000); // some large number
_cancelSource.Cancel();
TraceMessage("Task cancellation requested."); // Last thing traced
try
{
bool allStopped = await this.AllJobsCompleted;
TraceMessage(string.Format("allStopped = '{0}'.", allStopped));
}
catch (Exception e)
{
TraceMessage(e.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
我的期望是这样的:
当我使用WPF表单应用程序调试它时,我得到了这个.
但是,当我将其作为服务安装时:
我需要做些什么来确保OnStop不会杀死我的并行异步作业并等待TaskCompletionSource?
Ste*_*ary 12
你的问题OnStop是async void.所以,当它做await this.AllJobsCompleted,实际发生的事情是,它返回的OnStop,其中SCM解释为已经停止,并终止该进程.
这是您需要阻止任务的罕见情况之一,因为您无法OnStop在任务完成之后返回.
这应该这样做:
protected override void OnStop()
{
this.RequestAdditionalTime(100000); // some large number
_cancelSource.Cancel();
TraceMessage("Task cancellation requested."); // Last thing traced
try
{
bool allStopped = this.AllJobsCompleted.GetAwaiter().GetResult();
TraceMessage(string.Format("allStopped = '{0}'.", allStopped));
}
catch (Exception e)
{
TraceMessage(e.Message);
}
}
Run Code Online (Sandbox Code Playgroud)