有没有一种方法可以使 运行 方法使用 cts.Cancel(); 立即停止?

Is there a way I can cause a running method to stop immediately with a cts.Cancel();

我有创建 CancellationTokenSource 并将其传递给方法的代码。

我在另一个发出 cts.Cancel();

的应用程序中有代码

有没有一种方法可以使该方法立即停止,而不必等待 while 循环中的两行代码完成?

请注意,如果它导致我可以处理的异常,我会没事的。

public async Task OnAppearing()
{
   cts = new CancellationTokenSource();
   await GetCards(cts.Token);
}

public async Task GetCards(CancellationToken ct)
{
   while (!ct.IsCancellationRequested)
   {
      App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts);
      await CheckAvailability();
   }
}

我可以建议:

  1. 修改 GetViewablePhrases 和 CheckAvailability,以便您可以将 CancellationToken 传递给它们;
  2. 在这些函数中使用ct.ThrowIfCancellationRequested()
  3. 尝试/捕获 GetCards 中的 OperationCanceledException;

至于你的功能,我不知道它们在内部是如何工作的。但是,假设您在其中一个内部有一个很长的 运行 迭代:

CheckAvailability(CancellationToken ct)
{
    for(;;) 
    {
        // if cts.Cancel() was executed - this method throws the OperationCanceledException
        // if it wasn't the method does nothing
        ct.ThrowIfCancellationRequested(); 
        ...calculations... 
    } 
}

或者假设您要在其中一个函数中访问您的数据库,并且您知道这个过程需要一段时间:

CheckAvailability(CancellationToken ct)
{
    ct.ThrowIfCancellationRequested();
    AccessingDatabase();
}

这不仅会阻止您的函数继续执行,还会将执行者任务状态设置为 TaskStatus.Canceled

并且不要忘记捕捉异常:

public async Task GetCards(CancellationToken ct)
{
   try
   {
      App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts, ct);
      await CheckAvailability(ct);
   }
   catch(OperationCanceledException ex)
   {
       // handle the cancelation...
   }
   catch
   {
       // handle the unexpected exception
   }
}

如果您同意取消任务而不是取消任务,则可以使用可取消包装器。如果取消,基础任务将继续 运行,但包装器将在取消时立即完成。

public static Task AsCancelable(this Task task,
    CancellationToken cancellationToken)
{
    var cancelable = new Task(() => { }, cancellationToken);
    return Task.WhenAny(task, cancelable).Unwrap();
}

public static Task<T> AsCancelable<T>(this Task<T> task,
    CancellationToken cancellationToken)
{
    var cancelable = new Task<T>(() => default, cancellationToken);
    return Task.WhenAny(task, cancelable).Unwrap();
}

用法示例:

await GetCards(cts.Token).AsCancelable(cts.Token);

此扩展方法也可以使用 TaskCompletionSource<T>(而不是 Task<T> 构造函数)实现。