English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french
查看: 18|回复: 0

Winform-耗时操作导致界面渲染滞后

[复制链接]
查看: 18|回复: 0

Winform-耗时操作导致界面渲染滞后

[复制链接]
查看: 18|回复: 0

341

主题

0

回帖

1033

积分

金牌会员

积分
1033
okkkk

341

主题

0

回帖

1033

积分

金牌会员

积分
1033
2025-2-6 23:11:12 | 显示全部楼层 |阅读模式
原因:
某些耗时操作阻塞了主线程。
理解上述原因,需先搞清楚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之后跟随一个简单的耗时操作帮助理解。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

341

主题

0

回帖

1033

积分

金牌会员

积分
1033

QQ|智能设备 | 粤ICP备2024353841号-1

GMT+8, 2025-3-10 15:06 , Processed in 1.353235 second(s), 27 queries .

Powered by 智能设备

©2025

|网站地图