当前位置: 首页 > news >正文

【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.控件介绍 进度条通常用于显示代码的执行进程进度&#xff0c;在一些复杂功能交互体验时告知用户进程还在继续。 在属性栏中&#xff0c;有三个值常用&#xff1a; Value表示当前值&#xff0c;Minimum表示进度条范围下限&#xff0c;Maximum表示进度条范围上限。 2.简单实…...

深入浅出3D感知中的优化与基于学习的技术1(原创系列)

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

【CentOS 7 上安装 Oracle JDK 8u333】

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

Nginx 常用配置与应用

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

基于Springboot的智慧养老中心管理系统

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

数据结构笔记第3篇:双向链表

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

详细对比Java SPI、Spring SPI 和 Dubbo SPI

SPI&#xff08;Service Provider Interface&#xff09;概述 定义&#xff1a;SPI是一种动态替换发现机制&#xff0c;用于实现接口与实现的解耦&#xff0c;提高框架的可扩展性。核心思想&#xff1a;解耦和方便扩展。 Java SPI 约定规范&#xff1a; 扩展类文件放在META-…...

CPU的核心数和线程数

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

电脑游戏录屏,3款实用软件推荐给你

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

C#桌面应用开发:番茄定时器

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

PHP智慧门店微信小程序系统源码

&#x1f50d;【引领未来零售新风尚】&#x1f50d; &#x1f680;升级启航&#xff0c;智慧零售新篇章&#x1f680; 告别传统门店的束缚&#xff0c;智慧门店v3微信小程序携带着前沿科技与人性化设计&#xff0c;正式启航&#xff01;这个版本不仅是对过往功能的全面优化&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有了简单的了解&#xff0c;接…...

【稳定检索/投稿优惠】2024年教育、人文发展与艺术国际会议(EHDA 2024)

2024 International Conference on Education, Humanities Development and Arts 2024年教育、人文发展与艺术国际会议 【会议信息】 会议简称&#xff1a;EHDA 2024 大会时间&#xff1a;点击查看 截稿时间&#xff1a;点击查看 大会地点&#xff1a;中国北京 会议官网&#…...

Docker拉取失败,利用 Git将 Docker镜像重新打 Tag 推送到阿里云等其他公有云镜像仓库里

目录 一、开通阿里云容器镜像服务 二、Git配置 三、去DockerHub找镜像 四、编写images.txt文件 ​五、演示 六、其他注意事项 最近一段时间 Docker 镜像一直是 Pull 不下来的状态&#xff0c;想直连 DockerHub 是几乎不可能的。更糟糕的是&#xff0c;很多原本可靠的国内…...

【区分vue2和vue3下的element UI Breadcrumb 面包屑组件,分别详细介绍属性,事件,方法如何使用,并举例】

在 Vue 2 中&#xff0c;Element UI 提供了 el-breadcrumb 面包屑组件&#xff0c;而在 Vue 3 中&#xff0c;Element UI 的官方版本并没有直接更新以支持 Vue 3&#xff0c;但有一个类似的库叫做 Element Plus&#xff0c;它是为 Vue 3 设计的。 Vue 2 Element UI 在 Vue 2…...

gdb调试命令大全

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

ESP32之arduino环境安装及点灯

目录 前言 前两天安装了VS&#xff43;&#xff4f;&#xff44;&#xff45;&#xff0c;奈何资源找的困难&#xff0c;于是咨询淘宝客服&#xff0c;他说&#xff41;&#xff52;&#xff44;&#xff55;&#xff49;&#xff4e;&#xff4f;用的多,资源多.然后就安装了a…...

查看VUE中安装包依赖的版本号

查看VUE中安装包依赖的版本号 全部依赖包版本查看某个依赖的例&#xff1a;查看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搭建…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...