Task异步练习(进度条)

发布时间:2026/7/8 2:02:55

Task异步练习(进度条) WinForm窗体设计代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace 进度条 { public partial class Form1 : Form { private CancellationTokenSource _cts;//通行证 private bool _isPausefalse;//暂停标记 private bool _isRunningfalse;//运动标记 private int _currentNum 0;//值 public Form1() { InitializeComponent(); progressBar1.Minimum 0;//设置最小进度条 progressBar1.Maximum 100;//设置最大进度条 progressBar1.Value 0;//进度初始值 dataGridView1.Columns.Add(colNum, 数字);//在表格中添加列列名显示在表格中列名 dataGridView1.Columns.Add(colVal, 值); } private async Task RunLoopAsync(CancellationToken token)//从开启按钮传递过来的通行证用来监听取消信号 { await Task.Run(async () { for (; _currentNum 100; _currentNum) { token.ThrowIfCancellationRequested(); // 暂停阻塞逻辑 while (_isPause) { await Task.Delay(1000, token); } int val _currentNum * 10; // 后台子线程必须Invoke切UI线程更新控件 this.Invoke(new Action(() { progressBar1.Value _currentNum; label1.Text $当前进度{_currentNum}/100,数字值{val}; dataGridView1.Rows.Add(_currentNum, val); })); await Task.Delay(500, token); } // for循环执行完毕全部数字跑完 this.Invoke(new Action(() { label1.Text 全部执行完毕; MessageBox.Show(循环数字已到达100任务自动结束); })); _currentNum 0; this.Invoke(new Action(() { progressBar1.Value 0; })); }, token); // Task.Run 闭合 传入取消令牌 } private void btnPause_Click(object sender, EventArgs e) { if (!_isRunning) return; _isPause true; label1.Text 【已暂停】; } private void btnContinue_Click(object sender, EventArgs e) { if(!_isRunning||!_isPause) return; _isPausefalse; } private void btnCancel_Click(object sender, EventArgs e) { if(!_isRunning) return; _cts?.Cancel(); label1.Text null; dataGridView1.Rows.Clear(); progressBar1.Value 0; _currentNum 0; } private async void btnStart_Click(object sender, EventArgs e) { if (_isRunning) { MessageBox.Show(任务正在运行请勿重复开启); return; } _isRunning true; _isPause false; _cts new CancellationTokenSource(); CancellationToken token _cts.Token; try { await RunLoopAsync(token); } catch (OperationCanceledException) { label1.Text 任务已取消; } catch (Exception ex) { MessageBox.Show($运行异常{ex.Message}); } finally { _isRunning false; _cts?.Dispose(); _cts null; } } } }WinForm 异步后台进度条【暂停、继续、取消、断点续跑】终极知识总结一、整体功能你当前代码实现点击开启后台线程循环 0~100每 500ms 刷新进度条、Label、DataGridView支持暂停 / 继续软暂停不销毁任务、可续跑支持取消硬终止任务、清空界面防止重复开启多任务断点续跑暂停 / 取消后再次开启从上次数字继续自带异常捕获、资源释放、线程安全、UI 不卡顿二、全局变量 4 个必考csharp运行private CancellationTokenSource _cts; // 任务取消器发停止信号 private bool _isPause false; // 暂停标记 private bool _isRunning false; // 任务运行锁防重复启动 private int _currentNum 0; // 全局记录当前循环数字实现断点续跑作用一句话_cts负责取消任务_isPause负责暂停 / 继续_isRunning负责防止多开_currentNum负责断点续跑三、窗体构造函数知识点csharp运行progressBar1.Minimum 0; progressBar1.Maximum 100; progressBar1.Value 0; dataGridView1.Columns.Add(colNum, 数字); dataGridView1.Columns.Add(colVal, 值);进度条范围0~100和循环完全对齐代码动态创建表格两列无需手动设计四、核心重点为什么你的代码是真正后台线程关键区别你之前最大的疑惑1.async / await不会开后台线程2.Task.Run才会开后台线程你现在正确代码csharp运行await Task.Run(async () { // 这里 100% 后台子线程 });所以循环、计算、Delay全部跑在线程池后台不卡 UI必须 Invoke 更新控件否则报错跨线程五、核心方法 RunLoopAsync 逐知识点1. 方法标准规范csharp运行private async Task RunLoopAsync(CancellationToken token)自定义异步方法必须返回Task不能 async voidtoken接收取消信号用来随时终止循环2. 断点续跑 for 循环高频考点csharp运行for (; _currentNum 100; _currentNum)没有初始化语句循环变量用全局字段暂停、取消后数字不会丢 →实现断点续跑3. 任务取消检测csharp运行token.ThrowIfCancellationRequested();检测是否点击了取消点击取消直接抛异常 → 终止后台任务4. 软暂停逻辑重点csharp运行while (_isPause) { await Task.Delay(1000, token); }不销毁任务、不退出循环原地无限等待 →暂停改_isPausefalse→立刻继续5. Invoke 跨线程更新 UI必考csharp运行this.Invoke(new Action(() { progressBar1.Value _currentNum; label1.Text $当前进度{_currentNum}/100,数字值{val}; dataGridView1.Rows.Add(_currentNum, val); }));为什么必须 Invoke循环代码在后台子线程WinForm 控件只能由 UI 主线程访问子线程改控件 报错Invoke把子线程代码切回 UI 主线程执行6. 异步延时csharp运行await Task.Delay(500, token);不阻塞线程、不卡界面带 token取消时立刻中断等待六、任务跑完收尾逻辑csharp运行this.Invoke(new Action(() { label1.Text 全部执行完毕; MessageBox.Show(循环数字已到达100任务自动结束); })); _currentNum 0;跑完归零下次从头开始七、四个按钮逻辑总结超级清晰1. 开启按钮核心入口判断_isRunning防止重复开启创建_cts取消源传递 token 给后台任务try-catch捕获取消异常、程序异常finally 必执行释放资源、解锁任务状态2. 暂停按钮csharp运行_isPause true;后台while进入死循环等待 → 暂停3. 继续按钮csharp运行_isPause false;退出 while 循环 → 继续跑4. 取消按钮csharp运行_cts.Cancel();给后台发终止信号清空表格、进度条、数字八、三大核心机制区别考试必考1. 后台线程机制Task.Run→ 真正后台运行UI 不卡、必须 Invoke2. 暂停机制软暂停布尔变量控制任务不销毁、线程不退出、可续跑3. 取消机制硬终止CancellationTokenSource→ 强制终止任务抛取消异常九、异常处理机制OperationCanceledException用户手动取消任务 →正常预期操作通用 Exception 程序 Bug、计算错误、控件错误 →兜底保护程序不崩溃十、资源释放重要csharp运行finally { _isRunning false; _cts?.Dispose(); _cts null; }无论成功、报错、取消一定执行释放取消令牌资源防止内存泄漏十一、你代码的完美架构总结背诵版Task.Run开启后台线程 → UI 永不卡死全局变量记录状态→ 实现暂停、继续、续跑、防多开token 令牌→ 安全取消任务Invoke→ 解决跨线程 UI 报错async/await→ 优雅异步不阻塞try-catch-finally→ 安全稳定、资源不泄漏十二、最终一句话超级总结Task.Run 负责后台运行while (_isPause) 负责暂停CancellationToken 负责取消全局变量负责续跑、防多开Invoke 负责跨线程更新 UIasync/await 负责不卡界面

相关新闻