C# 如何优雅地取消正在运行的任务(续)
在上一篇C# 如何优雅地取消正在运行的任务 虽然取消了未结束的异步任务,但是被调用的同步方法仍未结束;代码不够优雅,所以在查看了B站博主的这个C#如何在异步任务中调用及取消一个长时间运行的同步方法(其一)视频后,发现他的做法比较优雅;
注意:这个👆视频介绍的方法适用于.NET Framework平台,在.NET CORE平台下已经不再适用,如果你是.NET CORE平台 请看C#如何在异步任务中调用及取消一个长时间运行的同步方法(其二)
由于我使用的是.NET Framework平台,所以下面的方法可以使用,👉这个是博主给出的gits链接CancelableProcessTask.cs,稍稍改写了连接中给出的代码,便有了下面的方法
public static class CancelableThreadTask
{
public static Task RunAsync(this Action action, CancellationToken token, Action onCompletedSuccessfully = null)
{
// 轻量级Task对象制造器
var tcs = new TaskCompletionSource<string>();
// 新开一个线程去执行同步方法
var thread = new Thread(() =>
{
try
{
action();
// 同步方法执行完成 通知外部任务结束
tcs.SetResult("Success");
// 执行任务结束回调方法 为什么方法定义时要传递这个入参?
// 想想:如果调用方直接调用RunAsync()而不是使用awit RunAsync(),那他万一又关心方法什么时候执行完成呢?这个回调是不是就很有必要。
onCompletedSuccessfully?.Invoke();
}
catch (Exception ex)
{
if (ex is ThreadAbortException)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetException(ex);
}
}
});
// 取消令牌的Register可以帮我们监视是否有取消操作发生
token.Register(() =>
{
// 若有取消操作发生 则干掉执行同步方法(即:那个入参action)所在线程
thread.Abort();
// _thread.Join();
// 轻量级Task对象生成器也调用一个取消方法,告诉外层等待方:你等待的任务已经取消
tcs.TrySetCanceled();
});
thread.Start();
// 对外承诺生成一个任务
return tcs.Task;
}
}
使用示例:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using CancelableDemo;
using ThirdPartyLib;
namespace CancelableApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private int orderNo = 1;
private CancellationTokenSource cts = new CancellationTokenSource();
private async void RunBtn_OnClick(object sender, RoutedEventArgs e)
{
// 每次执行任务前 都尝试取消一下之前的任务
try
{
cts.Cancel();
}
finally
{
cts.Dispose();
cts = new CancellationTokenSource();
}
try
{
await new Action(() =>
{
var o = new ThirdPartyClass();
// throw new Exception("--00");
var resp = o.LongRunningJob($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}");
}).RunAsync( cts.Token,OnComplete);
}
catch (TaskCanceledException ee)
{
Console.WriteLine("取消");
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
private void OnComplete()
{
Console.WriteLine("执行结束");
}
}
}
运行效果:
总结,当三方API中只给出了同步接口,同时这个接口还非常耗时的情况下,
- 如果想实现在第二次调用时,结束掉上次还未返回的任务,那么C# 如何优雅地取消正在运行的任务 这个就够了;
- 如果不仅想结束掉未返回的任务,还希望将三方API中的同步方法也结束掉,则需要使用到Thread操作,在判断到取消操作后,结束掉响应的thread就ok了。

浙公网安备 33010602011771号