【发布时间】:2017-08-18 22:33:02
【问题描述】:
等待时间到期后,我需要取消正在运行 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);
}
【问题讨论】:
-
这取决于你的代码,你用什么来执行查询?有时可以将 cancelToken 作为参数传递给异步方法。请记住:在一定时间后取消 SQL 查询最好是通过将超时(毫秒)传递到执行查询的位置(而不是取消令牌)。如果您不知道何时停止(例如用户想要停止它),您只会使用取消令牌。
-
Maerlin,我添加了一些示例代码。我已经有单独的 sql 查询超时,但是我正在使用信号量小批量运行任务,所以说每个查询在 10 秒后超时,并且有 10 个这样的批次,相当于 100 秒运行时,我想在 10 秒后取消所有任务的执行。
-
阅读Stephen Cleary的优秀博客,里面有很多关于异步操作的文章
标签: c# asp.net parallel-processing task-parallel-library cancellation-token