我有一个主要是IO绑定的连续任务(后台拼写检查器与拼写检查服务器交谈)。有时,此任务需要暂停并稍后恢复,具体取决于用户活动。
虽然暂停/恢复基本上是async/await
所做的,但我发现很少有关于如何为异步方法实现实际暂停/播放逻辑的信息。 是否有推荐的模式?
我也考虑过使用Stephen Toub的AsyncManualResetEvent
,但认为这可能是一种矫枉过正的行为。
答案 0 :(得分:9)
AsyncManualResetEvent
正是您所需要的。但更好的解决方案是使用Stephen Toub的另一种方法:PauseToken
。它与AsyncManualResetEvent
的工作方式类似,不同之处在于它的接口专门用于此目的。
答案 1 :(得分:2)
当涉及异步/等待编程时,所有其他答案似乎都很复杂,或者缺少标记,因为它们占用了CPU昂贵的线程,并可能导致死锁。经过大量的试验,错误和许多死锁之后,这终于可以用于我的高使用率测试。
var isWaiting = true;
while (isWaiting)
{
try
{
//A long delay is key here to prevent the task system from holding the thread.
//The cancellation token allows the work to resume with a notification
//from the CancellationTokenSource.
await Task.Delay(10000, cancellationToken);
}
catch (TaskCanceledException)
{
//Catch the cancellation and it turns into continuation
isWaiting = false;
}
}
答案 2 :(得分:1)
好吧,也许这应该得到答案,但我对C#并不熟悉,我在这里没有MonoDevelop,现在是凌晨3点,所以请怜悯。
我建议这样的事情
class Spellchecker
{
private CancellationTokenSource mustStop = null;
private volatile Task currentTask = null;
//TODO add other state variables as needed
public void StartSpellchecker()
{
if (currentTask != null)
{
/*
* A task is already running,
* you can either throw an exception
* or silently return
*/
}
mustStop = new CancellationTokenSource();
currentTask = SpellcheckAsync(mustStop.Token);
currentTask.Start();
}
private async Task SpellcheckAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested))
{
/*
* TODO perform spell check
* This method must be the only one accessing
* the spellcheck-related state variables
*/
}
currentTask = null;
}
public async Task StopSpellchecker()
{
if (currentTask == null)
{
/*
* There is no task running
* you can either throw an exception
* or silently return
*/
}
else
{
/*
* A CancelAfter(TimeSpan) method
* is also available, which might interest you
*/
mustStop.Cancel();
//Remove the following lines if you don't want to wait for the task to actually stop
var task = currentTask;
if (task != null)
{
await task;
}
}
}
}
答案 3 :(得分:1)
它对我有用
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskTest2
{
class Program
{
static ManualResetEvent mre = new ManualResetEvent(false);
static void Main(string[] args)
{
mre.Set();
Task.Factory.StartNew(() =>
{
while (true)
{
Console.WriteLine("________________");
mre.WaitOne();
}
} );
Thread.Sleep(10000);
mre.Reset();
Console.WriteLine("Task Paused");
Thread.Sleep(10000);
Console.WriteLine("Task Will Resume After 1 Second");
Thread.Sleep(1000);
mre.Set();
Thread.Sleep(10000);
mre.Reset();
Console.WriteLine("Task Paused");
Console.Read();
}
}
}