Winform-耗时操作导致界面渲染滞后
原因:
某些耗时操作阻塞了主线程。
理解上述原因,需先搞清楚Winform线程机制。主要有以下2点特性:1.单线程模型;2.依赖消息循环。
1.单线程模型
Winform 默认是单线程。通常,所有的UI操作,包括控件更新、事件处理,都由主线程管理(也就是UI线程)。
任何在事件处理程序中运行的代码都会占用主线程。如果某个事件中有耗时很多的操作,就会阻塞线程。比如有时PictureBox.Image的显示会滞后。
下面代码中,pictureBox1的显示会有滞后。背后的工作原理是:
“pictureBox1.Image = image0”运行完成后,系统只是将 pictureBox1 的 Image 属性更新,但不会立即触发控件绘制。(实际的绘制操作是由消息循环处理的,在 WM_PAINT 消息中完成)
pictureBox1的属性设置之后,如果紧接着有耗时操作占用UI线程,就会导致WM_PAINT无法及时处理,所以不能及时绘制。
最佳解决办法:
避免在 UI 线程执行耗时任务。将耗时任务移到后台线程,可以确保 UI 线程始终空闲以处理消息循环,比如使用 Task.Run 或 async/await。
private void button2_Click(object sender, EventArgs e)
{
using (var session = new InferenceSession(_modelPath))
{
...... // 无关代码
Bitmap image0 = new Bitmap(_imagePath);
pictureBox1.Image = image0;
// 以下是某耗时操作
DenseTensor<float> inputTensor = PreprocessImage(image0);
......
}
}
补充一点:只有主线程可以访问或更新控件;如果要从其他线程访问、更新控件,要使用特定的线程间通讯,必须使用 Control.Invoke 或 Control.BeginInvoke 方法将操作封送到 UI 线程执行。如果在后台线程中得到某个变量,需要渲染到主界面,就需要用到Control.Invoke等方法。
2.依赖消息循环
UI线程依赖消息循环(Message Loop)处理用户输入、标点击等操作和系统消息。Application.Run 启动时,UI线程进入消息循环状态,不断从消息队列中提取消息并分发到对应控件处理。上述提到的线程阻塞实际上是阻塞了消息循环。
上述2个特性明白之后,就能理解原因中提到的阻塞了。如果不理解,可以尝试在pictureBox1.Image之后跟随一个简单的耗时操作帮助理解。
Winform-耗时操作导致界面渲染滞后的更多相关文章
- C# Winform频繁刷新导致界面闪烁解决方法
C#Winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供的默认双缓冲将 ...
- winform频繁刷新导致界面闪烁解决方法
转自龙心文 原文 winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供 ...
- BroadCastReceiver中耗时操作导致ANR
現象:廣播接收器中進行耗時的I/O操作導致ANR. 查資料發現每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 该对 ...
- Winform 界面执行耗时操作--UI卡顿假死问题
UI卡顿假死问题 误区1:使用不同的线程操作UI控件和耗时操作(即,跨线程操作UI控件CheckForIllegalCrossThreadCalls = false;), 注意:此处只是为了记录... ...
- winform 开发中 把耗时操作 封装起来 异步执行(.net 4.0)
.先定义一个 BackgroundTask.cs 代码如下: public class BackgroundTask { private static WaitDialogForm LoadingDl ...
- 修复UE4编辑器,ClearLog操作导致的崩溃
UE4 4.24.3版本,编辑器Output Log窗口中,右键--Clear Log操作很大概率会导致编辑器奔溃:解决办法: 相关文件: Engine\Source\Developer\Output ...
- ASP.NET服务器端执行耗时操作的工作记录
公司之前有这样一个业务需求: 一名同事做出文件a0和b0,然后将a0加密为a1.b0加密为b1:再将文件a0.a1.b0和b1上传至服务器M:同时要将服务器N上的数据表添加一条记录,该记录的ID就是前 ...
- RxJava2-后台执行耗时操作,实时通知 UI 更新(一)
一.前言 接触RxJava2已经很久了,也看了网上的很多文章,发现基本都是在对RxJava的基本思想介绍之后,再去对各个操作符进行分析,但是看了之后感觉过了不久就忘了. 偶然的机会看到了开源项目 Rx ...
- AsyncTask 进行耗时操作和UI 更新
相信各位对 AsyncTask 不会陌生,虽然它有如下弊端: 1. 如果在activiy内部new 一个AsyncTask, 横竖屏切换生成一个新的activity,等结果返回时,处理不好容易出现NP ...
- WinForm查询大数据界面假死,使用异步调用解决
用DataGridView无分页绑定一个几千条数据的查询,查询的时候界面直接卡死十几秒,用户体验非常不好,因此用异步操作解决界面卡死的问题原本场景:点击[查询]后,界面直接卡死优化场景:点击[查询]后 ...
随机推荐
- 2023NOIP A层联测32 T4 红楼 ~ Eastern Dream
2023NOIP A层联测32 T4 红楼 ~ Eastern Dream 根号分治加分块. Ps:分块后面真的用的多. 思路 考虑根号分治,将 \(x\) 分为 \(x \leq \sqrt n\) ...
- NZOJ 模拟赛7
T1 字符串 小X十分热爱学习.有一天,他刚学完"漂亮的k字符串"的概念:给定长度为n的字符串和整数k,k能整除n,如果该字符串满足以下两个条件: s是一个回文串,即对于任意1≤i ...
- vite 分包打包
1.概述 在使用vite打包的时候,一般情况会将依赖包和源码打包到一起,这样的问题是,一般情况依赖包一般情况是不变的,如果打包到一起,程序更新时,就会因为打包指纹发生变化而重新下载,如果进行分包,如果 ...
- springboot 参数注解 注入参数
什么时注解参数 说明 我们在 使用spring mvc 的时候会使用这样的注解 @ResponseBody 这样,spring mvc 会将 客户端传来的数据,自动构建成 相应类型的对象. 有些情况下 ...
- 使用Tesseract进行图片文字识别
Tesseract介绍 Tesseract 是一个开源的光学字符识别(OCR)引擎,最初由 HP 在 1985 年至 1995 年间开发,后来被 Google 收购并开源.Tesseract 支持多种 ...
- GPU 驱动漏洞:窥探驱动漏洞利用的技术奥秘
GPU 驱动漏洞:窥探驱动漏洞利用的技术奥秘 本文尝试以 GPU 漏洞为引介绍围绕 GPU 驱动这一攻击面,安全研究人员对内核漏洞利用技术做的一些探索. 背景介绍 目前移动 SOC 平台上由多个硬件模 ...
- C/C++源码扫描系列- codeql 篇
首发于 https://xz.aliyun.com/t/9275 概述 codeql 是一个静态源码扫描工具,支持 c, python, java 等语言,用户可以使用 ql 语言编写自定义规则识别软 ...
- 【分块】LibreOJ 6282 数列分块入门6
题目 https://loj.ac/p/6282 题解 数据范围 \(1 \leq n \leq 10^5\),因此进行分块最多分 \(\sqrt{10^5} ≈ 318\) 块.且数据是随机生成的, ...
- 【Amadeus原创】群晖关闭局域网发现
套件中心-媒体服务器,卸载.
- Linux FTP 服务搭建
Linux FTP 服务搭建 1.安装vsftp 1.1.使用yum进行安装vsftp [root@localhost ~]# yum -y install vsftpd 1.2.配置文件目录 [ro ...