如何停止使用async/await的项目中后台运行的Worker Thread?
如何停止使用async/await的后台Worker Thread?
我在项目中使用了async和await,现在想要停止正在后台运行的Worker Thread,请问该如何实现?我尝试了以下代码:
private CancellationTokenSource cancellationToken; private async void method1(int parameter) { //do something } private async Task method2(int parameter) { await Task.Run(() =>{ method1(parameter); Task.Delay(1000).Wait(); }, cancellationToken.Token); } private async void bt_start_Click(object sender, EventArgs e) { cancellationToken = new CancellationTokenSource(); await method2(123); } private async void bt_stop_Click(object sender, EventArgs e) { if (cancellationToken != null) { cancellationToken.Cancel(); } }
你的代码存在的问题
method1是async void,无法跟踪执行状态,也无法响应取消请求Task.Run内部用Task.Delay(1000).Wait()同步阻塞线程,且全程未检查取消令牌,调用Cancel()后不会触发停止- 取消令牌仅传给了
Task.Run,但内部的异步/同步操作完全没感知到取消信号
正确实现方式
要实现可取消的异步任务,核心是让所有耗时操作都感知并响应CancellationToken,具体步骤如下:
1. 修正异步方法返回类型,传递取消令牌
除UI事件处理程序(必须用async void),其他异步方法都用async Task,并将CancellationToken传入需要响应取消的方法中。
2. 在操作中检查取消请求
在耗时循环或异步等待时,定期检查取消令牌:
- 用
token.ThrowIfCancellationRequested()主动抛出取消异常终止任务 - 给支持取消的异步方法(比如
Task.Delay)传入令牌,让异步操作本身响应取消
3. 处理取消异常
在启动任务的地方捕获OperationCanceledException,这是.NET中取消操作的标准异常。
修改后的完整代码示例
private CancellationTokenSource _cancellationTokenSource; // 改为async Task,接受取消令牌 private async Task Method1(int parameter, CancellationToken token) { // 模拟耗时业务逻辑,循环中定期检查取消 while (true) { // 检查是否收到取消请求,若已取消则抛出异常终止任务 token.ThrowIfCancellationRequested(); // 执行你的业务操作 // do something // 异步等待,避免阻塞线程,同时传入令牌响应取消 await Task.Delay(100, token); } } private async Task Method2(int parameter, CancellationToken token) { // 直接调用异步方法,无需额外用Task.Run(如果Method1本身是异步的) await Method1(parameter, token); } private async void BtStart_Click(object sender, EventArgs e) { // 先终止之前可能在运行的任务 _cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Dispose(); // 创建新的取消令牌源 _cancellationTokenSource = new CancellationTokenSource(); try { await Method2(123, _cancellationTokenSource.Token); } catch (OperationCanceledException) { // 任务被取消时的处理逻辑,比如提示用户 // MessageBox.Show("任务已停止"); } } private void BtStop_Click(object sender, EventArgs e) { // 触发取消请求 _cancellationTokenSource?.Cancel(); // 释放资源 _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; }
特殊情况:如果Method1是同步耗时操作
如果Method1是纯同步的CPU密集型操作,需要用Task.Run放到后台线程,但同样要在内部检查取消令牌:
private async Task Method1(int parameter, CancellationToken token) { await Task.Run(() => { while (true) { token.ThrowIfCancellationRequested(); // 执行同步耗时操作 // do something } }, token); }
内容的提问来源于stack exchange,提问作者Headshot
相关产品推荐
相关产品推荐

