【C#】ProgressBar进度条异步编程思想
1.控件介绍
进度条通常用于显示代码的执行进程进度,在一些复杂功能交互体验时告知用户进程还在继续。
在属性栏中,有三个值常用:
Value表示当前值,Minimum表示进度条范围下限,Maximum表示进度条范围上限。
2.简单实例
在一个界面下,点击按钮,进度条加载,用label显示运行耗时。
在Form1.cs中,添加点击Button1按钮功能:
private async void button1_Click(object sender, EventArgs e)
{Stopwatch stopwatch = new Stopwatch();stopwatch.Start();button1.Enabled = false;//防止重复点击progressBar1.Value = 0;int progressStep = 10;for (int i = 0; i <= progressBar1.Maximum; i = i + progressStep){await Task.Delay(100);progressBar1.Value = i;}button1.Enabled = true;stopwatch.Stop();label1.Text = $"运行耗时:{stopwatch.ElapsedMilliseconds}ms";MessageBox.Show("ok");
}
3.异步编程思想:
异步编程是一种编程范式,它允许程序在执行耗时操作时,不阻塞主线程或调用线程,从而提高程序的响应性和性能。简单来说,异步编程使得程序在等待某些操作(如网络请求、文件I/O、数据库查询等)的完成时,可以继续处理其他任务。
3.1 为什么需要异步编程?
在同步编程模式下,当程序执行一个耗时操作(例如读取文件或从网络获取数据)时,整个程序会暂停,主线程被堵塞,直到这个操作完成。这会导致程序变得不可响应,特别是在需要处理用户交互的应用程序中。
异步编程通过允许程序处理其他任务而不会被耗时操作阻塞,解决了这一问题。例如,在用户接口应用程序中,异步编程可以防止界面“卡死”,从而提升用户体验。
3.2 异步编程流程:
功能代码如下:模拟一个等待执行
private async Task LoadDataAsync()
{await Task.Delay(5000); // 异步等待 5 秒Console.WriteLine("数据加载完成"); // 5 秒后执行
}
(1)当线程执行到await关键字标识的位置后,系统将方法挂起,返回控制权给调用者。
(2)任务调度器记录 Task.Delay(5000),在 5 秒后标记任务为完成。
(3)5秒后,任务调度器标记 Task.Delay(5000) 完成。调度器触发回调,通知方法恢复执行。打印"数据加载完成"。
(4)在挂起期间,用户可以自行操作,不会造成UI阻塞。
3.3 await是什么?
await是C#中的关键字,用于异步编程等待异步操作的完成,不会阻塞当前进程。通常与async关键字一起用。
3.4 async是什么?
async也是C#中的关键字,用于修饰方法、匿名函数或者lambda表达式。通常和await一起用,指示他们包含异步操作。
3.5 Task是什么?
异步方法通常返回 Task 或 Task 对象,表示一个异步操作的进行。
Task 类还可以用于表示和管理异步操作。
以上三个关键字总结:async 修饰的方法通常返回 Task 或 Task < T >,而 await 用于等待任务的完成。
3.6 应用例子:
在图形用户界面(GUI)应用程序中,阻塞主线程会导致用户界面变得不可响应。例如,如果用户点击一个按钮触发一个耗时操作,整个界面会在操作完成之前冻结,无法响应用户的其他操作。
单纯摆出异步编程的例子无法体会精髓,先用一个同步编程的来对比:
同步编程:
点击button1按钮,开始执行功能代码,代码功能放到了另一个方法中去,该方法的功能就是单纯进行线程休眠,模拟耗时操作。
private void button1_Click(object sender, EventArgs e)
{Stopwatch stopwatch = new Stopwatch();stopwatch.Start();button1.Enabled = false;//防止重复点击Form1Bar.Value = 0;int progressStep = 10;for (int i = 0; i <= Form1Bar.Maximum; i = i + progressStep){// 同步方法,阻塞UI线程LoadData();Form1Bar.Value = i;}button1.Enabled = true;stopwatch.Stop();label1.Text = $"运行耗时:{stopwatch.ElapsedMilliseconds}ms";MessageBox.Show("ok");
}
模拟耗时方法:
private void LoadData()
{System.Threading.Thread.Sleep(1000);// 会强制阻塞线程
}
测试卡死按钮:
private void button2_Click(object sender, EventArgs e)
{textBox1.Text = "异步编程,UI未卡死";
}
private void button3_Click(object sender, EventArgs e)
{textBox1.Text = string.Empty;
}
运行过程中无法点击测试按钮,UI进程阻塞,GUI卡死。
异步编程(主窗口进度条):
异步编程会挂起当前await的耗时方法,不会阻塞当前线程,用户可以操作其他。
private async void button1_Click(object sender, EventArgs e)
{Stopwatch stopwatch = new Stopwatch();stopwatch.Start();button1.Enabled = false;//防止重复点击Form1Bar.Value = 0;int progressStep = 10;for (int i = 0; i <= Form1Bar.Maximum; i = i + progressStep){// 同步方法,阻塞UI线程await LoadData();Form1Bar.Value = i;}button1.Enabled = true;stopwatch.Stop();label1.Text = $"运行耗时:{stopwatch.ElapsedMilliseconds}ms";MessageBox.Show("ok");
}
private async Task LoadData()
{//System.Threading.Thread.Sleep(5000);// 会强制阻塞线程await Task.Delay(500);
}
异步编程(弹出窗口进度条):
Form1作为主界面,只放Button1和label1两个控件,点击开始后,弹出Form2进度条加载。
不仅实现弹出窗口进度条,还通过异步编程实现。
关键代码:
private async void button1_Click(object sender, EventArgs e)
{button1.Enabled = false;//防止重复点击Form2 form2 = new Form2();form2.Show();Stopwatch stopwatch = new Stopwatch();stopwatch.Start();for(int i = 0; i<= form2.Form2Bar.Maximum; i+= 10){await LoadData();form2.Form2Bar.Value = i;}button1.Enabled = true;stopwatch.Stop();label1.Text = $"运行耗时:{stopwatch.ElapsedMilliseconds}ms";MessageBox.Show("ok");form2.Close();
}
private async Task LoadData()
{await Task.Delay(500);
}
4.更进一步
仔细阅读上述代码可以发现,每次进度条加载是通过i来控制的,i每次随着休眠结束会自增10,这样确实可以均匀控制进度条增长。
但是现在有这样一个问题,在实际项目中,我们随着处理的数据量不同,并不知道每次运行的固定时间,换言之,可能并不是每次均匀增长一个固定值。
在之前先介绍一下一种特殊的函数-----回调函数
4.1 回调函数
回调函数,是指函数通过参数传给另一个函数,在满足特定的条件下由后者调用。
在异步编程思想中,当某个操作完成后,回调函数会被执行,处理或相应发生的事件。
下面是一个简单的代码展示:
// 定义一个回调函数
void CallbackFunction(string message)
{Console.WriteLine(message);
}// 定义一个异步函数,接受回调函数作为参数
void doSomethingAsync(Action<string> callback)
{// 模拟异步操作Task.Run(() =>{// 模拟一些工作Task.Delay(1000).Wait();// 调用回调函数callback("Operation completed!");});
}// 使用异步函数并传递回调函数
doSomethingAsync(CallbackFunction);
CallbackFunction(string message)是一个回调函数,当有字符串类型的参数传入时,会进行打印操作。
doSomethingAsync(Action callback)是一个异步函数(内部含有Task.Run),内部模拟了一个耗时异步操作,在结束后调用回调函数。
4.2 控制进度条
在不同任务耗时不一样的前提下,控制进度条的增长可以通过下面两种方法:
(1)将任务分解成为多个子任务,每个任务结束后手动增加,更新进度条。(看起来一卡一卡的)
(2)通过IProgress < T > 接口实现任务的进度报告,实时更新进度条。(进度均匀,更优雅)
两种方法其实很类似,都是需要去做一个标记,然后更新。
如果实在无法分割子任务,可使用进度条Marquee样式,实现类似跑马灯的效果,只告诉用户程序在运行,不知道结束的时间。
关键代码实例,只保留核心部分:
progress是一个报告器,接受参数,触发内部的Lambda回调函数,更新进度条。
private async void Button_Click(object sender, EventArgs e)
{// 创建一个进度报告器,更新进度条var progress = new Progress<int>(percent =>{progressBar.Value = percent; // 更新进度条});// 启动长时间运行的任务await ExecuteLongRunningTask(progress);// ...
}
private async Task ExecuteLongRunningTask(IProgress<int> progress)
{int totalSteps = 100; // 任务的总步数(假设任务可以分为100步)for (int i = 0; i < totalSteps; i++){// 模拟长时间任务await Task.Delay(100); // 每步等待100毫秒// 报告进度progress.Report((i + 1) * 100 / totalSteps);}
}
相关文章:

【C#】ProgressBar进度条异步编程思想
1.控件介绍 进度条通常用于显示代码的执行进程进度,在一些复杂功能交互体验时告知用户进程还在继续。 在属性栏中,有三个值常用: Value表示当前值,Minimum表示进度条范围下限,Maximum表示进度条范围上限。 2.简单实…...

深入浅出3D感知中的优化与基于学习的技术1(原创系列)
近期几乎看了所有有关NERF技术论文,本身我研究的领域不在深度学习技术方向,是传统的机器人控制和感知。所以总结了下这部分基于学习的感知技术,会写一个新的系列教程讲解这部分三维感知技术的发展到最新的技术细节,并支持自己最近…...

【CentOS 7 上安装 Oracle JDK 8u333】
文章目录 下载 Oracle JDK 8u333:上传 RPM 包到服务器安装 Oracle JDK设置 JAVA_HOME 环境变量验证 下载 Oracle JDK 8u333 访问 https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html 找到 JDK 8u333 版本,并下载适用于 L…...

Nginx 常用配置与应用
Nginx 常用配置与应用 官网地址:https://nginx.org/en/docs/ 目录 Nginx 常用配置与应用 Nginx总架构 正向代理 反向代理 Nginx 基本配置反向代理案例 负载均衡 Nginx总架构 进程模型 正向代理 反向代理 Nginx 基本配置反向代理案例 负载均衡 Nginx 基本配置…...

基于Springboot的智慧养老中心管理系统
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Springboot的智慧养老中心管理系统,…...

数据结构笔记第3篇:双向链表
1、双向链表的结构 注意:这里的 "带头" 跟前面我们说的 "头结点" 是两个概念,实际前面的在单链表阶段称呼不严谨,但是为了同学们更好的理解就直接称为单链表的头结点。 带头链表里的头结点,实际为 "哨兵…...

详细对比Java SPI、Spring SPI 和 Dubbo SPI
SPI(Service Provider Interface)概述 定义:SPI是一种动态替换发现机制,用于实现接口与实现的解耦,提高框架的可扩展性。核心思想:解耦和方便扩展。 Java SPI 约定规范: 扩展类文件放在META-…...

CPU的核心数和线程数
CPU的核心数和线程数 一、关系: 1、线程数可以模拟出不同的CPU核心数。 CPU的核心数指的是硬件上存在着几个核心,而线程数可以模拟出多个核心数的功能。线程数越多,越有利于同时运行多个程序,因为线程数等同于在某个瞬间CPU能同…...

电脑游戏录屏,3款实用软件推荐给你
在电竞游戏热潮席卷全球的今天,电脑游戏录屏早已不再是简单的画面捕捉,它成为了记录电竞风采、打造专属游戏记忆的重要手段。通过游戏录屏,我们可以定格游戏中的精彩瞬间,重温那些令人热血沸腾的电竞时刻。那么,在进行…...

C#桌面应用开发:番茄定时器
C#桌面应用开发:番茄定时器 1、环境搭建和工程创建: 步骤一:安装visual studio2022 步骤二:新建工程 2、制作窗体部件 *踩过的坑: (1)找不到工具箱控件,现象如下:…...

PHP智慧门店微信小程序系统源码
🔍【引领未来零售新风尚】🔍 🚀升级启航,智慧零售新篇章🚀 告别传统门店的束缚,智慧门店v3微信小程序携带着前沿科技与人性化设计,正式启航!这个版本不仅是对过往功能的全面优化&a…...

SerDes介绍以及原语使用介绍(2)OSERDESE2原语仿真
文章目录 前言一、SDR模式1.1、设计代码1.2、testbench代码1.3、仿真分析 二、DDR模式下2.1、设计代码2.2、testbench代码2.3、仿真分析 三、OSERDES2级联3.1、设计代码3.2、testbench代码3.3、代码分析 前言 上文通过xilinx ug471手册对OSERDESE有了简单的了解,接…...

【稳定检索/投稿优惠】2024年教育、人文发展与艺术国际会议(EHDA 2024)
2024 International Conference on Education, Humanities Development and Arts 2024年教育、人文发展与艺术国际会议 【会议信息】 会议简称:EHDA 2024 大会时间:点击查看 截稿时间:点击查看 大会地点:中国北京 会议官网&#…...

Docker拉取失败,利用 Git将 Docker镜像重新打 Tag 推送到阿里云等其他公有云镜像仓库里
目录 一、开通阿里云容器镜像服务 二、Git配置 三、去DockerHub找镜像 四、编写images.txt文件 五、演示 六、其他注意事项 最近一段时间 Docker 镜像一直是 Pull 不下来的状态,想直连 DockerHub 是几乎不可能的。更糟糕的是,很多原本可靠的国内…...

【区分vue2和vue3下的element UI Breadcrumb 面包屑组件,分别详细介绍属性,事件,方法如何使用,并举例】
在 Vue 2 中,Element UI 提供了 el-breadcrumb 面包屑组件,而在 Vue 3 中,Element UI 的官方版本并没有直接更新以支持 Vue 3,但有一个类似的库叫做 Element Plus,它是为 Vue 3 设计的。 Vue 2 Element UI 在 Vue 2…...

gdb调试命令大全
基本命令 #gdb test test是要调试的程序,由gcc test.c -g -o test生成。进入后提示符变为(gdb) 。 start : 指令会执行程序至main() 主函数的起始位置,即在main() 函数的第一行语句处停止执行(该行代码尚未执行) cont…...

ESP32之arduino环境安装及点灯
目录 前言 前两天安装了VScode,奈何资源找的困难,于是咨询淘宝客服,他说arduino用的多,资源多.然后就安装了a…...

查看VUE中安装包依赖的版本号
查看VUE中安装包依赖的版本号 全部依赖包版本查看某个依赖的例:查看stompjs 应用命令npm ls stompjs 全部依赖包版本 使用npm命令 使用 npm ls 命令可以列出项目中所有已安装的依赖包及其版本。 使用 npm list --depth1 命令可以列出项目中直接依赖的包及其版本&a…...

博途通讯笔记1:1200与1200之间S7通讯
目录 一、添加子网连接二、创建PUT GET三、各个参数的意义 一、添加子网连接 二、创建PUT GET 三、各个参数的意义...

Kafka搭建(集群版)
Kafka单机版 部署前提 VMware环境 : 两台centos系统 Jdk包:jdk-8u202-linux-x64.tar.gz Kafka包:kafka_2.12-3.5.0.tgz Zookeeper包:apache-zookeeper-3.7.2-bin.tar.gz 百度网盘自取: 链接: https://pan.baidu.com/s/11EWuhBoSmH3musd_3Rgodw?pwde32t 提取码: e32t Kafka搭建…...

【康复学习--LeetCode每日一题】3115. 质数的最大距离
题目: 给你一个整数数组 nums。 返回两个(不一定不同的)质数在 nums 中 下标 的 最大距离。 示例 1: 输入: nums [4,2,9,5,3] 输出: 3 解释: nums[1]、nums[3] 和 nums[4] 是质数。因此答案是…...

【yolov8系列】ubuntu上yolov8的开启训练的简单记录
前言 yolov8的广泛使用,拉取yolov8源码工程,然后配置环境后直接运行,初步验证自己数据的检测效果,在数据集准备OK的情况下 需要信手拈来,以保证开发过程的高效进行。 本篇博客更注意为了方便自己使用时参考。顺便也记录…...

Scala学习笔记15: 文件和正则表达式
目录 第十五章 文件和正则表达式1- 读取行2- 从URL或者其它源读取3- 写入文本文件4- 序列化5- 正则表达式6- 正则表达式验证输入数据格式end 第十五章 文件和正则表达式 1- 读取行 在Scala中读取文件中的行可以通过不同的方法实现 ; 一种常见的方法是使用 scala.io.Source 对…...

外卖员面试现状
说明: 以下身份角色用符号代替 # 面试官 $ 求职者 # 看了您的简历你有两年半的送外卖经验,可以简单说一下您平时是怎么送外卖的吗? $ 我首先在平台接单然后到店里取餐,取到餐后到顾客留下的地址,再通知顾客取餐 # 你们也用电动…...

异步加载与动态加载
异步加载和动态加载在概念上有相似之处,但并不完全等同。 异步加载(Asynchronous Loading)通常指的是不阻塞后续代码执行或页面渲染的数据或资源加载方式。在Web开发中,异步加载常用于从服务器获取数据,而不需要用户等…...

MUNIK解读ISO26262--什么是DFA
我们在学习功能安全过程中,经常会听到很多安全分析方法,有我们熟知的FMEA(Failure Modes Effects Analysis)和FTA(Fault Tree Analysis)还有功能安全产品设计中几乎绕不开的FMEDA(Failure Modes Effects and Diagnostic Analysis),相比于它们…...

启动spring boot项目停止 提示80端口已经被占用
可能的情况: 检查并结束占用进程: 首先,你需要确定哪个进程正在使用80端口。在Windows上,可以通过命令行输入netstat -ano | findstr LISTENING | findstr :80来查看80端口的PID,然后在任务管理器中结束该进程。在...

SOLIDWORKS分期许可(订阅形式),降低前期的投入成本!
SOLIDWORKS 分期许可使您能够降低前期软件成本,同时提供对 SOLIDWORKS 新版本和升级程序的即时访问,以及在每个期限结束时调整产品的灵活性,帮助您跟上市场需求和竞争压力的步伐。 目 录: ★ 1 什么是SOLIDWORKS分期许可 ★ 2 …...

详细分析Spring Boot 数据源配置的基本知识(附配置)
目录 前言1. 基本知识2. 模版3. 实战经验前言 对于Java的基本知识推荐阅读: java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)【Java项目】实战CRUD的功能整理(持续更新)1. 基本知识 包括数据源的概念、连接池的作用、多数据源的实现与管理、Druid 连接池…...

海思SD3403/SS928V100开发(15)9轴IMU ICM-20948模块SPI接口调试
1.前言 芯片平台: 海思SD3403/SS928V100 操作系统平台: Ubuntu20.04.05【自己移植】 9轴IMU模块:ICM-20948 通讯接口: SPI 模块datasheet手册: https://download.csdn.net/download/jzwjzw19900922/89517096 2. 调试记录 2.1 pinmux配置 #spi0 bspmm 0x0102F01D8 …...