取消长期运行的任务

时间:2019-06-11 08:40:03

标签: c# asp.net-mvc concurrency

我正在asp.net mvc应用程序中运行CPU绑定任务。一些用户可以“订阅”此任务,应将完成情况通知他们。但是,当任务没有订阅者时,必须将其取消。任务通过ajax请求开始,并在调用.abort()方法时取消。在控制器中,我将CancellationToken作为确定取消的参数。

问题在于,当一个订户呼叫中止(取消订阅)时,尽管其他用户正在等待结果,但链接的令牌会取消任务。检查某些条件后如何取消CancellationToken?每次循环迭代后,我都无法检查IsCancellationRequested属性,因为我包装了非异步方法。

任务完成后,将通过SignalR通知用户。我试图实现ConcurrentDictionary在取消任务是否有订阅者之前进行检查。

private async Task<Diff> CompareAsync(Model modelName, CancellationToken ct)
        {
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    ct.ThrowIfCancellationRequested();

                        return _someServiceName.CompareLines(modelName.LinesA, modelName.LinesB, ct);


                }, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {

                //do some things
            }

        }

我需要这样的东西,但不能提出任何(不难看)的想法:

private async Task<Diff> CompareAsync(Model modelName, CancellationToken ct)
        {
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    using (var source = new CancellationTokenSource())
                    {

                        if (ct.IsCancellationRequested && CompareService.SharedComparison.TryGetValue(modelName.Hash, out var usersCount) && usersCount < 2)
                        {
                            source.Cancel();

                        }

                        return _someServiceName.CompareLines(modelName.LinesA, modelName.LinesB, source.Token);  
                    }


                }, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {

                //do some things
            }

        }

1 个答案:

答案 0 :(得分:0)

您将必须保持线程安全订阅者计数(最有可能使用lock),并且仅在令牌0时取消令牌。

private int _subscribers;
private object _sync = new object();

private AddSubscribers()
{
   Lock(_sync )
   {
       // do what ever you need to do
       _subscribers++;
   }
}

private RemoveSubscribers()
{
   Lock(_sync )
   {
       // do what ever you need to do
       _subscribers--;
       if(_subscribers <= 0)
       {
           // cancel token
       }
   }
}

注意 :显然,这不是一个完整的解决方案,给想象力留下了很多印象