C# 可暂停&;可恢复异步任务队列
我已经基于我在这里找到的东西实现了一个工作队列>…但是在实现附加功能时遇到了麻烦 我取出了C# 可暂停&;可恢复异步任务队列,c#,.net,async-await,task-queue,cancellation,C#,.net,Async Await,Task Queue,Cancellation,我已经基于我在这里找到的东西实现了一个工作队列>…但是在实现附加功能时遇到了麻烦 我取出了Func,用icommand(持有自己的取消令牌)替换了它们,并打算添加Pause(),Resume(),Save()和Restore()方法。因此,OnFormClose()我可以暂停队列处理,并提示用户决定是“等待队列完成”(即恢复),还是“立即退出”(即保存并退出) 公共类WqController { 私有只读队列_Queue=new Queue(); 专用任务队列处理器; 专用ICommandu c
Func
,用icommand(持有自己的取消令牌)替换了它们,并打算添加Pause()
,Resume()
,Save()
和Restore()
方法。因此,OnFormClose()
我可以暂停队列处理,并提示用户决定是“等待队列完成”(即恢复),还是“立即退出”(即保存并退出)
公共类WqController
{
私有只读队列_Queue=new Queue();
专用任务队列处理器;
专用ICommandu curCommand;
公共无效排队(ICommand命令)
{
_queue.Enqueue(命令);
如果(_queueProcessor==null)_queueProcessor=ProcessQueue();
}
专用异步任务ProcessQueue()
{
尝试
{
而(_queue.Count!=0)
{
_curCommand=_queue.Peek();
尝试
{
等待任务。运行(()=>\u curCommand.Execute());
}
捕获(操作取消异常)
{
控制台写入线(“队列暂停”);
返回;
}
捕获(例外)
{
Console.WriteLine(“无法执行命令”);
}
_queue.Dequeue();
}
}
最后
{
_queueProcessor=null;
_curCommand=null;
}
}
公共异步任务取消()
{
_curCommand.Cts.Cancel(true);
等待队列处理器;
}
公众简历()
{
_queueProcessor=ProcessQueue();
}
}
Save()
和Restore()
工作正常,所以我没有在这里包括它们。Cancel()
间歇/不可靠地工作,而Restore()
似乎根本不起作用(让我困惑的是,我基本上是在尝试与Enqueue()
方法相同的重新启动)。我已经开始工作了,我认为应该在这里概述我的解决方案
事实证明,我对取消令牌的使用有点随意,这妨碍了该类按预期运行。例如,以下问题是相关的:
if(_curCommand.Cts.Token.iscancellationrequest)返回来解决代码>紧跟在\u queue.Dequeue()之后代码>
\u curCommand.InvalidateCancellationToken()
通过将令牌设置为null来实现这一点,然后我的命令在下次调用时刷新令牌public class WqController
{
private readonly Queue<ICommand> _queue = new Queue<ICommand>();
private Task _queueProcessor;
private ICommand _curCommand;
public void Enqueue(ICommand command)
{
_queue.Enqueue(command);
if (_queueProcessor == null) _queueProcessor = ProcessQueue();
}
private async Task ProcessQueue()
{
try
{
while (_queue.Count != 0)
{
_curCommand = _queue.Peek();
try
{
await Task.Run(() => _curCommand.Execute());
}
catch (OperationCanceledException)
{
_curCommand.InvalidateCancellationToken();
Console.WriteLine("QUEUE PAUSED");
return;
}
catch (Exception)
{
Console.WriteLine("FAILED TO EXECUTE COMMAND");
}
_queue.Dequeue();
if (_curCommand.Cts.Token.IsCancellationRequested) return;
}
}
finally
{
_queueProcessor = null;
_curCommand = null;
}
}
public async Task Cancel()
{
_curCommand.Cts.Cancel(true);
await _queueProcessor;
}
public void Resume()
{
_queueProcessor = ProcessQueue();
}
}
公共类WqController
{
私有只读队列_Queue=new Queue();
专用任务队列处理器;
专用ICommandu curCommand;
公共无效排队(ICommand命令)
{
_queue.Enqueue(命令);
如果(_queueProcessor==null)_queueProcessor=ProcessQueue();
}
专用异步任务ProcessQueue()
{
尝试
{
而(_queue.Count!=0)
{
_curCommand=_queue.Peek();
尝试
{
等待任务。运行(()=>\u curCommand.Execute());
}
捕获(操作取消异常)
{
_curCommand.InvalidateCancellationToken();
控制台写入线(“队列暂停”);
返回;
}
捕获(例外)
{
Console.WriteLine(“无法执行命令”);
}
_queue.Dequeue();
if(_curCommand.Cts.Token.IsCancellationRequested)返回;
}
}
最后
{
_queueProcessor=null;
_curCommand=null;
}
}
公共异步任务取消()
{
_curCommand.Cts.Cancel(true);
等待队列处理器;
}
公众简历()
{
_queueProcessor=ProcessQueue();
}
}
这一切现在似乎都运行得非常顺利,这是对我以前使用的后台工作队列实现的一个重大改进。很难看出这个类如何保持任何不变量。例如,如果
状态!=WqStatus.暂停
然后恢复只是默默地失败。添加断言,确保仅当状态为“暂停”时才调用“恢复”。另外,您假定\u queueProcessor==null
。也为它添加一个断言。诸如此类。我认为我所看到的问题与地位或数量无关。恢复代码肯定正在运行。我想我会在这方面调整代码。当我打开Resume()
时,\u queueProcessor
的状态为“WaitingForActivation”,如果这有帮助的话?在我看来,我们缺少确定发生了什么的代码。例如,您谈到取消,但您在代码中真正检查您的CancellationToken
?我看不到这一部分。@YuvalItzchakov:我正在执行一个\u curCommand.Cts.Token.ThrowIfCancellationRequested()
,就在通过此队列的命令调用的任何代码中的任何长时间运行的任务之前。您的评论刚刚帮助我解释了Cancel()
的间歇性。如果在最后一次取消后调用cancel c
public class WqController
{
private readonly Queue<ICommand> _queue = new Queue<ICommand>();
private Task _queueProcessor;
private ICommand _curCommand;
public void Enqueue(ICommand command)
{
_queue.Enqueue(command);
if (_queueProcessor == null) _queueProcessor = ProcessQueue();
}
private async Task ProcessQueue()
{
try
{
while (_queue.Count != 0)
{
_curCommand = _queue.Peek();
try
{
await Task.Run(() => _curCommand.Execute());
}
catch (OperationCanceledException)
{
_curCommand.InvalidateCancellationToken();
Console.WriteLine("QUEUE PAUSED");
return;
}
catch (Exception)
{
Console.WriteLine("FAILED TO EXECUTE COMMAND");
}
_queue.Dequeue();
if (_curCommand.Cts.Token.IsCancellationRequested) return;
}
}
finally
{
_queueProcessor = null;
_curCommand = null;
}
}
public async Task Cancel()
{
_curCommand.Cts.Cancel(true);
await _queueProcessor;
}
public void Resume()
{
_queueProcessor = ProcessQueue();
}
}