C#取消正在执行长时间运行的sql查询的任务列表
我需要取消等待时间到期后运行SQL查询的任务列表。我可以实现CancellationToken来取消任务。但是取消是合作的,因此这意味着我必须在每一步之前检查操作中的取消令牌状态。但在我的例子中,sql查询需要很长时间,我只能在执行查询之前或之后检查cancel令牌状态。在后一种情况下,它是无用的,那么如何根据cancel令牌状态取消这些任务中的查询执行呢C#取消正在执行长时间运行的sql查询的任务列表,c#,asp.net,parallel-processing,task-parallel-library,cancellation-token,C#,Asp.net,Parallel Processing,Task Parallel Library,Cancellation Token,我需要取消等待时间到期后运行SQL查询的任务列表。我可以实现CancellationToken来取消任务。但是取消是合作的,因此这意味着我必须在每一步之前检查操作中的取消令牌状态。但在我的例子中,sql查询需要很长时间,我只能在执行查询之前或之后检查cancel令牌状态。在后一种情况下,它是无用的,那么如何根据cancel令牌状态取消这些任务中的查询执行呢 public void EnqueueTask(Action action, CancellationToken cancelToken =
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);
}
public void排队任务(操作操作,CancellationToken cancelToken=default(CancellationToken))
{
var任务=新任务(操作、取消令牌、TaskCreationOptions.LongRunning);
if(_workTaskQueue.TryAdd(任务))
{
TaskHandler?调用
(新任务处理争论)
{
ISTaskAdded=true,
Message=“任务已添加到队列”,
PendingTaskCount=\u workTaskQueue.Count,
});
}
其他的
{
TaskHandler?调用
(新任务处理争论)
{
ISTaskAdded=false,
Message=“将任务添加到队列时超时”,
PendingTaskCount=\u workTaskQueue.Count,
});
}
}
public void出列任务(int-maxConcurrency,CancellationToken-ct)
{
var tasks=新列表();
使用(SemaphoreSlim concurrency semaphore=new SemaphoreSlim(maxConcurrency))
{
foreach(在_workTaskQueue.GetConsumingEnumerable()中的var task)
{
尝试
{
如果(!(task.IsCanceled)&&task.Status==TaskStatus.Created)
{
任务。添加(任务);
task.Start();
}
}
最后{
并发Maphore.Release();
}
}
}
Task.WaitAll(tasks.ToArray());
}
void StartWorker()
{
Task.Factory.StartNew(()=>
{
尝试
{
taskQueue.DequeueTask(maxConcurrency,cancellationToken);
}
最后{
锁(同步对象)
{
IsCompleted=真;
}
//Logger.Info(“关闭工作任务!!!”;
}
},TaskCreationOptions.LongRunning);
}
编写一个使用新线程启动查询的任务,该任务可以继续检查CancelationToken的状态,并在需要时终止该线程
例如,您可以扩展任务并添加此功能。您需要在作为操作实例传递到排队任务方法的函数中使用取消令牌 例如,以下代码显示了如何使用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作为参数传递给异步方法。请记住:在特定时间后取消SQL查询最好是将超时(毫秒)传递到执行查询的位置(而不是cancellationtoken)。如果您不知道何时停止(例如,用户想要停止),您只会使用cancellationtoken。Maerlin,我添加了一些示例代码。我已经为sql查询设置了单独的超时时间,但我正在使用信号量以小批量运行任务,因此假设批次中的每个查询在10秒后超时,并且有10个类似的批次,这相当于100秒的运行时间,相反,我想在10秒后取消所有任务的执行。阅读优秀的博客,其中有很多关于异步操作的文章。你想在取消令牌周围放置一个using块。注册,在
ExecuteNonQuery
之后立即关闭感谢@Tim,修正了。u Show cancellationToken,但是你没有显示它属于哪个类或函数,这也解决了我的问题,但是我使用Olexiy的答案,因为它看起来更简单。非常感谢。无法给你+1,因为我没有足够的重复次数:|