暂停/恢复异步任务的模式?

时间:2013-10-27 00:38:16

标签: c# .net asynchronous async-await

我有一个主要是IO绑定的连续任务(后台拼写检查器与拼写检查服务器交谈)。有时,此任务需要暂停并稍后恢复,具体取决于用户活动。

虽然暂停/恢复基本上是async/await所做的,但我发现很少有关于如何为异步方法实现实际暂停/播放逻辑的信息。 是否有推荐的模式?

我也考虑过使用Stephen Toub的AsyncManualResetEvent,但认为这可能是一种矫枉过正的行为。

4 个答案:

答案 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();
                }
            }
        }