有没有一种方法可以使 运行 方法使用 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();
}
}
我可以建议:
- 修改 GetViewablePhrases 和 CheckAvailability,以便您可以将 CancellationToken 传递给它们;
- 在这些函数中使用ct.ThrowIfCancellationRequested();
- 尝试/捕获 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>
构造函数)实现。
我有创建 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();
}
}
我可以建议:
- 修改 GetViewablePhrases 和 CheckAvailability,以便您可以将 CancellationToken 传递给它们;
- 在这些函数中使用ct.ThrowIfCancellationRequested();
- 尝试/捕获 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>
构造函数)实现。