C#取消正在执行长时间运行的SQL查询的任务列表

时间:2017-08-18 22:33:02

标签: c# asp.net parallel-processing task-parallel-library cancellation-token

我需要在等待时间到期后取消正在运行SQL查询的任务列表。我可以实现CancellationToken来取消任务。但取消是合作的,所以这意味着我必须在每一步之前检查我的行动中的取消令牌状态。但在我的情况下,sql查询是需要很长时间的查询,我只能在查询执行之前或之后检查取消令牌状态。在后一种情况下,它是无用的,那么如何根据取消令牌状态取消这些任务中的查询执行?

public void EnqueueTask(Action action, CancellationToken cancelToken = default(CancellationToken))
{
    var task = new Task(action, cancelToken, TaskCreationOptions.LongRunning);
    if (_workTaskQueue.TryAdd(task))
    {
        TaskHandler?.Invoke
            (new TaskProcessingArguments
            {
                ISTaskAdded = true,
                Message = "Task Added to Queue",
                PendingTaskCount = _workTaskQueue.Count,
            });
    }
    else
    {
        TaskHandler?.Invoke
            (new TaskProcessingArguments
            {
                ISTaskAdded = false,
                Message = "Timedout while adding Task to Queue",
                PendingTaskCount = _workTaskQueue.Count,
            });
    }
}

public void DequeueTask(int maxConcurrency, CancellationToken ct)
{
    var tasks = new List<Task>();
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
    {
        foreach (var task in _workTaskQueue.GetConsumingEnumerable())
        {
            try
            {
                if (!(task.IsCanceled) && task.Status == TaskStatus.Created)
                {
                    tasks.Add(task);
                    task.Start();
                }
            }
            finally {
                concurrencySemaphore.Release();
            }
        }
    }
    Task.WaitAll(tasks.ToArray());
}

    void StartWorker()
    {
        Task.Factory.StartNew(() =>
        {
            try
            {
                taskQueue.DequeueTask(maxConcurrency, cancellationToken);
            }
            finally {
                lock (syncObj)
                {
                    IsCompleted = true;
                }
                //Logger.Info("Closing Worker task!!!");
            }
        }, TaskCreationOptions.LongRunning);
    }

2 个答案:

答案 0 :(得分:2)

您需要在作为操作实例传递的函数中使用 CancellationToken EnqueueTask 方法。

E.g。以下代码显示了 CancellationToken 如何用于终止SQL命令的执行:

    using (SqlConnection conn = new SqlConnection(sqlConnection))
    {
        conn.Open();
        var cmd = conn.CreateCommand();

        using (cancellationToken.Register(() => cmd.Cancel()))
        {
            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
    }

答案 1 :(得分:0)

编写一个使用新线程启动查询的任务,任务可以继续检查CancelationToken的状态并在需要时终止该线程。

您可以扩展任务&lt;&gt;并添加此功能。