• WPF线程模型


    1. 渲染系统概述

    WPF 采用保留模式渲染系统 (Retained Mode Rendering System),该系统可分为 UI 线程和复合线程两个主要部分,两者协作完成 WPF 应用程序的渲染工作。

    1.1 立即模式GUI和保持模式GUI#

    图形 API 可分为保留模式API 和即时模式API。 Direct2D 是一种即时模式 API。 WPF 是保留模式 API 的一个示例。

    1.1.1. 立即模式GUI#

    保留模式 API 是声明性的。 应用程序从图形基元(如形状和线条)构造场景。 图形库将场景的模型存储在内存中。 为了绘制帧,图形库将场景转换为一组绘图命令。 在帧之间,图形库将场景保留在内存中。 若要更改呈现的内容,应用程序会发出命令来更新场景,例如添加或删除形状。 然后,该库负责重绘场景。

    每渲染一帧时(很多机器都可以做到1秒钟60帧),渲染库需要执行渲染每个元素的指令,所以这种库无需记住你已经渲染了什么东西,反正每次都会全部重绘。会持续消耗你的CPU和GPU资源。

    即时模式的GUI库常用于更动态的元素表现,比如实时图表,动画,特效,游戏等,任何一个像素的改变,都会快速的呈现给你的用户。

    img

    1.1.2. 保持模式GUI#

    即时模式 API 是过程性的。 每次绘制新帧时,应用程序都会直接发出绘图命令。 图形库不会在帧之间存储场景模型。 相反,应用程序会跟踪场景。

    由开发者调用渲染库的API,适时的重绘需需要改变的元素。这就需要渲染库有能力记住之前都渲染了什么东西,所以也会占用更多的内存。

    保留模式的GUI库通常更容易使用,使开发更快,但它们也通常也会需要更多的开销,比如要记住元素的位置、层级、遮盖情况等等。

    img

    保留模式 API 可能更易于使用,因为 API 会为你执行更多工作,例如初始化、状态维护和清理。 另一方面,它们通常不太灵活,因为 API 施加了自己的场景模型。 此外,保留模式 API 可能具有更高的内存要求,因为它需要提供通用场景模型。 使用即时模式 API,可以实现有针对性的优化。

    2. 线程模型

    2.1. 概述#

    WPF 应用程序有两类线程负责渲染:一个用于管理 UI 叫 UI 线程,另一个用于处理渲染叫复合线程,也叫呈现线程。 当 UI 线程接收输入、处理事件、绘制屏幕和运行应用程序代码时,复合线程通过隐藏方式在后台高效运行。

    2.1.1. UI线程#

    UI 线程是 WPF 应用程序最重要的线程。它负责处理所有用户交互事件,如按钮单击、菜单选择以及键盘和鼠标输入。它还负责计算 UI 元素的布局、处理数据绑定、触发属性更改等工作。UI 线程是单线程的,这意味着在同一时间只能有一个操作在 UI 线程上运行。

    UI 线程在称为 Dispatcher 的对象内对工作项进行排队。 Dispatcher 基于优先级选择工作项,并运行每一个工作项直到完成。 每个 UI 线程必须具有至少一个 Dispatcher,且每个 Dispatcher 都可精确地在一个线程中执行工作项。

    UI 线程也可以启用多个,由于多线程程序既复杂又难以调试,因此当存在单线程解决方案时,应避免使用多线程程序。

    UI 线程的主要职责是:

    1. 计算布局和测量视觉(Visual)对象。
    2. 实现数据绑定和依赖属性系统。
    3. 处理用户输入和事件。
    4. 安排和分派渲染工作项给复合线程。

    总的来说,UI 线程的工作是计算最终结果,并安排复合线程执行渲染工作。

    2.1.2. 复合线程#

    复合线程负责 WPF 视觉层次结构的实际渲染工作。当应用程序的 UI 需要在屏幕上重新绘制时,复合线程就会介入,包括窗口大小调整、动画以及任何影响 UI 外观的操作。

    复合线程与 UI 线程紧密协作。UI 线程计算布局并安排 Visual 对象,复合线程会渲染 Visual 对象,并将其发送给桌面窗口管理器以在屏幕上显示。

    复合线程是一个线程池,包含若干个工作线程,线程数量通常与系统的 CPU 内核数量相同,可以在多个内核上并行工作,从而提高 WPF 应用程序 UI 操作的性能。

    复合线程的主要职责是:

    1. 生成可视化树中元素的位图。
    2. 应用效果(如3D变换、混合模式等)。
    3. 合成最终的渲染内容发送给桌面窗口管理器。

    2.2. UI线程和复合线程协作#

    UI 线程和复合线程是 WPF 渲染系统的两个重要部分,它们相互协作完成渲染工作:

    1. UI线程负责计算布局、测量元素大小、响应用户交互等。
    2. UI线程通过 VisualTarget.Render 方法将渲染工作项分派给复合线程线程池。
    3. 复合线程中的工作线程并行执行渲染工作,生成位图数据。
    4. 复合线程将最终的渲染结果提交给桌面窗口管理器显示。

    3. 性能优化

    若要生成响应迅速、用户友好的应用程序,诀窍在于通过保持工作项小型化来最大化 Dispatcher 吞吐量。 这样一来,工作项就不会停滞在 Dispatcher 队列中,因等待处理而过时。 输入和响应间任何可察觉的延迟都会让界面卡顿无响应,带来糟糕体验。

    需要注意的是,UI线程不应该执行长时间的操作,否则会导致UI无响应。相反,应该在后台线程上执行这些任务。

    WPF 应用程序在处理大型操作时,如涉及大型计算,或需要查询某些远程服务器上的数据库。通常情况下,解决方法是在单独的线程中处理大型操作,让 UI 线程更多倾向于处理 Dispatcher 队列中的工作项。大型操作完成后,再通过 Dispatcher 将结果发送到 UI 线程进行安全渲染。

    总的来说,UI 线程专注于用户交互和布局,而复合线程专注于高效呈现 UI。通过正确地利用这两个线程,可以构建响应灵敏且高效的 WPF 应用程序。

    参考引用:

    https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/threading-model?view=netframeworkdesktop-4.8&viewFallbackFrom=netdesktop-8.0

    https://learn.microsoft.com/zh-cn/windows/win32/learnwin32/retained-mode-versus-immediate-mode

    https://zhuanlan.zhihu.com/p/534695668

  • 相关阅读:
    列表和标签企业报告版的完整报告解决方案
    [附源码]计算机毕业设计基于springboot的网上点餐系统
    保姆教程angular8(一)
    12v24v60v高校同步降压转换芯片推荐
    登录应该是POST还是GET?
    深度学习(PyTorch)——卷积神经网络(CNN)基础篇
    用梯度下降算法极大化对数似然函数来估计参数
    c++ 程序中使用命令行
    java使用stream流把集合中元素的属性空值赋值为0,BigDecimal类型属性使用reduce()自定义运算符,避免计算的时候导致报错
    Vot-Toolkit环境配置指南
  • 原文地址:https://www.cnblogs.com/leolion/p/18075937