簡體   English   中英

C#取消正在執行長時間運行的SQL查詢的任務列表

[英]C# Cancel a list of tasks which are executing long running sql queries

等待時間到期后,我需要取消正在運行SQL查詢的任務列表。 我可以實現CancellationToken來取消任務。 但是取消是合作的,因此這意味着我必須在每一步之前檢查動作內部的取消令牌狀態。 但是在我的情況下,sql查詢是花費很長時間的查詢,並且我只能在查詢執行之前或之后檢查cancel令牌狀態。 在后一種情況下,它是無用的,那么如何根據取消令牌狀態在這些任務中取消查詢執行?

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);
    }

您需要在作為Action實例傳遞給EnqueueTask方法的函數中使用CancellationToken

例如,以下代碼顯示了如何將CancellationToken用於終止SQL命令的執行:

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

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

編寫一個使用新線程啟動查詢的任務,該任務可以繼續檢查CancellationToken的狀態,並在需要時終止該線程。

您可以擴展Task <>並添加此功能,例如。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM