3

『技术群里聊些啥』Task 不是你想 Cancel,想 Cancel 就能 Cancel

 2 years ago
source link: https://blog.51cto.com/MyIO/5283532
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

『技术群里聊些啥』Task 不是你想 Cancel,想 Cancel 就能 Cancel

原创

MyIO 2022-05-09 12:33:10 ©著作权

文章标签 技术交流 抛出异常 异步方法 文章分类 .Net 编程语言 阅读数144

在群里看到有人问如何取消这个 Task 的执行:

『技术群里聊些啥』Task 不是你想 Cancel,想 Cancel 就能 Cancel_技术交流

实际上这并不会取消​​S1eepMode1​​方法的执行:

『技术群里聊些啥』Task 不是你想 Cancel,想 Cancel 就能 Cancel_异步方法_02

这是为什么呢?

首先,让我们看看​​s_cts.Cancel()​​都做了啥:

public void Cancel() => Cancel(false);

public void Cancel(bool throwOnFirstException)
{
ThrowIfDisposed();
NotifyCancellation(throwOnFirstException);
}

private void NotifyCancellation(bool throwOnFirstException)
{
// If we're the first to signal cancellation, do the main extra work.
if (!IsCancellationRequested
&& Interlocked.CompareExchange(ref _state, NotifyingState, NotCanceledState) == NotCanceledState)
{
...
}
}

实际上,​​Cancel​​​方法仅仅是将变量​​_state​​​的值改为​​NotifyingState​​​。那​​Task.Run​​​传递​​s_cts.Token​​又有什么用呢?

public static Task<TResult> Run<TResult>(Func<Task<TResult>?> function, CancellationToken cancellationToken)
{
if (function == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function);

// Short-circuit if we are given a pre-canceled token
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<TResult>(cancellationToken);

...
}

原来,​是在创建 Task 前先检查令牌是否已经Cancel,以便快速终止。​​那么,到底怎么才能​​Cacel​​​已创建的​​Task​​呢?

其实,​​Task.Run​​​的方法实现已经告诉我们正确的解决方案,那就是判断​​cancellationToken.IsCancellationRequested​​:

public static async Task S1eepMode1(CancellationToken cancellationToken)
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
return;

...
}
}

另外,也可以采取抛出异常的方式:

public static async Task S1eepMode1(CancellationToken cancellationToken)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();

...
}
}

示例应用程序并不会捕获到这个异常,相关问题可以看我以前的文章《 ​如何保证执行异步方法时不会遗漏 await 关键字

在创建 Task 时请记住,即使你执行了令牌取消操作,也并不意味着 Task 会停止运行。

  • 收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK