C# 取消正在执行 long 运行 sql 查询的任务列表
C# Cancel a list of tasks which are executing long running sql queries
我需要在等待时间到期后取消 运行 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);
}
编写一个使用新线程启动查询的任务,该任务可以继续检查您的 CancellationToken 的状态并在需要时终止线程。
例如,您可以扩展 Task<> 并添加此功能。
您需要在作为 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();
}
}
我需要在等待时间到期后取消 运行 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);
}
编写一个使用新线程启动查询的任务,该任务可以继续检查您的 CancellationToken 的状态并在需要时终止线程。
例如,您可以扩展 Task<> 并添加此功能。
您需要在作为 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();
}
}