WPF高级学习(一)

文章目录

  • 一、理解进程和线程
      • 1. 进程:就像一个独立的“工厂”
        • 举例:
      • 2. 线程:就像工厂里的“工人”
        • 举例:
      • 总结:进程 vs 线程
  • 二、线程
      • 一、WPF 中的线程类型
      • 二、核心规则:线程亲和性(Thread Affinity)
      • 三、线程间通信的核心:Dispatcher
        • 1. Dispatcher 的工作原理
        • 2. 常用方法(见下表)
      • 四、线程使用示例
      • 五、常见线程问题及解决方案
      • 六、与其他技术的对比
      • 总结
  • 三、Dispatcher
      • 一、Dispatcher 的核心作用
      • 二、Dispatcher 的关键方法
      • 三、使用场景与实例
        • 1. 基础用法:获取 Dispatcher 实例
        • 2. 后台线程更新 UI(使用 `InvokeAsync`)
        • 3. 带优先级的操作
        • 4. 同步执行(`Invoke`)
      • 四、注意事项
      • 总结
  • 四、WPF里的线程和进程
      • 1. WPF中的进程:就像“整个剧院”
      • 2. WPF中的线程:就像“剧院里的工作人员”
        • (1)UI线程:“舞台总监”
        • (2)后台线程:“后台工作人员”
      • 关键区别:WPF线程 vs 普通Windows线程
        • 举例:WPF中下载图片并显示
      • 总结
  • 五、UI线程的简单使用说明
      • 一、UI线程的“样子”:它不是一个可见的实体,而是一种“执行角色”
      • 二、如何“使用”UI线程?
        • 1. 默认情况下:代码运行在UI线程中
        • 2. 后台线程如何与UI线程通信?
        • 3. 如何判断当前线程是否是UI线程?
      • 三、错误示例:后台线程直接操作UI(会崩溃)
      • 总结

一、理解进程和线程

在Windows系统中,进程线程是管理程序运行的两个核心概念,我们可以用“工厂”和“工人”来生动类比:

参考链接
一文带你搞懂C#多线程的5种写法

1. 进程:就像一个独立的“工厂”

  • 定义:进程是一个正在运行的程序(比如微信、记事本、浏览器),它拥有自己的“地盘”(独立的内存空间、资源),是系统分配资源的基本单位。
  • 特点:每个进程之间相互隔离,就像不同工厂之间用围墙隔开,彼此的资源(原材料、设备)不共享,一个工厂出问题(崩溃)不会直接影响其他工厂。
举例:
  • 当你打开“记事本”时,Windows会创建一个记事本进程:
    • 它会占用一块独立的内存(用来存你输入的文字);
    • 拥有自己的窗口资源(标题栏、输入区);
    • 即使你再打开一个新的记事本(另一个进程),两个记事本的内容也不会互相干扰(各自内存独立)。
  • 同理,你同时打开“微信”和“浏览器”,它们就是两个独立的进程,微信的内存数据(聊天记录)和浏览器的内存数据(网页缓存)完全分开。

2. 线程:就像工厂里的“工人”

  • 定义:线程是进程内部的“执行单元”,一个进程至少有一个线程(主线程),也可以有多个线程,它们共享进程的资源(内存、设备等),是系统调度执行的基本单位。
  • 特点:线程更轻量,多个线程在同一个进程内协作,就像工厂里的多个工人共用工厂的设备和原材料,效率更高,但需要协调工作(避免抢资源)。
举例:
  • 用“浏览器进程”来说:
    • 当你打开一个浏览器(比如Chrome),它首先会创建一个主线程(相当于“厂长”),负责显示窗口、处理地址栏输入等。
    • 你在浏览器里同时做三件事:
      1. 下载一个文件(线程A:专门负责网络下载,相当于“搬运工”);
      2. 播放网页里的视频(线程B:专门负责视频解码,相当于“播放员”);
      3. 拖动页面滚动条(线程C:专门负责界面刷新,相当于“清洁工”)。
    • 这三个线程都属于浏览器进程,共享浏览器的内存(比如下载的文件临时存在浏览器的缓存区),但各自干不同的活,让你感觉“同时”完成了多个操作。
  • 再比如“微信”进程:
    • 一个线程负责接收消息(监听网络),另一个线程负责刷新聊天窗口(显示新消息),还有一个线程负责检查更新——它们共享微信的账号数据、聊天记录(存在进程的内存里),协作完成微信的所有功能。

总结:进程 vs 线程

类比进程(工厂)线程(工人)
资源有独立内存、资源(围墙内的地盘)共享进程的资源(共用工厂设备)
独立性相互隔离,一个崩溃不影响其他同属一个进程,一个线程崩溃可能拖垮整个进程
数量系统中可同时存在多个独立进程一个进程可包含多个线程
核心作用作为资源分配的单位作为任务执行的单位

简单说:进程是“容器”,线程是“干活的”。一个进程里的多个线程协同工作,让程序能高效处理多任务;而多个进程则保证了不同程序之间的安全隔离。

二、线程

在 WPF 中,线程模型是其核心特性之一,尤其是与 UI 交互相关的线程规则,直接影响应用程序的稳定性和性能。以下是 WPF 线程模型的详细介绍:
深入浅出C#:章节 9: C#高级主题:多线程编程和并发处理

一、WPF 中的线程类型

WPF 应用程序通常涉及两种主要线程:

  1. UI 线程(主线程)

    • 是应用程序启动时自动创建的线程,负责创建和管理所有 UI 元素(如 WindowButtonTextBox 等)。
    • 处理用户输入(鼠标、键盘事件)、UI 渲染和布局计算。
    • 特点:一个 WPF 应用程序只有一个 UI 线程,所有 UI 操作必须在该线程上执行。
  2. 后台线程(工作线程)

    • 由开发者手动创建(如通过 TaskThread 等),用于执行耗时操作(如数据计算、文件读写、网络请求、串口通信等)。
    • 特点:不能直接操作 UI 元素,否则会抛出 InvalidOperationException(跨线程操作异常)。

二、核心规则:线程亲和性(Thread Affinity)

WPF 控件具有线程亲和性

  • 控件只能由创建它的线程(即 UI 线程)访问或修改其属性(如 TextVisibilityWidth 等)。
  • 后台线程若要操作 UI,必须通过 Dispatcher(UI 线程的调度器)将操作“委托”给 UI 线程执行。

为什么有这个规则?
WPF 的渲染引擎和布局系统不是线程安全的,单线程处理 UI 可以避免多线程并发修改导致的界面错乱或崩溃。

三、线程间通信的核心:Dispatcher

Dispatcher 是 UI 线程的“调度中心”,负责管理 UI 线程的工作项队列,是后台线程与 UI 线程通信的唯一安全方式。

1. Dispatcher 的工作原理
  • UI 线程运行时会不断从 Dispatcher 的队列中取出工作项并执行。
  • 后台线程通过 Dispatcher 的方法(如 InvokeAsyncBeginInvoke)将 UI 操作封装成工作项,加入队列。
  • Dispatcher 按优先级依次执行这些工作项,确保它们在 UI 线程上运行。
2. 常用方法(见下表)
方法作用适用场景
Invoke(Action)同步执行:阻塞当前线程,直到 UI 线程完成操作需要等待 UI 操作结果(如弹窗确认)
BeginInvoke(Action)异步执行:不阻塞当前线程,操作入队后立即返回无需等待结果的 UI 更新(如显示日志)
InvokeAsync(Action)异步执行:返回 Task,支持 await(推荐)现代异步编程模式,兼顾简洁性和可控性

四、线程使用示例

以“后台计算 + UI 实时更新”为例:

public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();// 启动后台任务StartBackgroundWork();}private void StartBackgroundWork(){// 创建后台线程(Task 自动管理线程池)Task.Run(() =>{for (int i = 0; i <= 100; i++){// 模拟耗时计算Thread.Sleep(100);int progress = i;// 关键:通过 Dispatcher 委托 UI 更新// 方法1:使用 InvokeAsync(推荐,支持 await)Dispatcher.InvokeAsync(() =>{// 此代码在 UI 线程执行,安全更新进度条progressBar.Value = progress;txtStatus.Text = $"进度:{progress}%";});// 方法2:使用 BeginInvoke(无返回值,纯异步)// Dispatcher.BeginInvoke(new Action(() =>// {//     progressBar.Value = progress;// }));}});}
}

五、常见线程问题及解决方案

  1. 跨线程操作异常

    • 错误表现:后台线程直接修改 TextBox.Text 等属性,抛出 InvalidOperationException
    • 解决:通过 Dispatcher 调度 UI 操作(如上述示例)。
  2. UI 线程阻塞

    • 错误表现:在 UI 线程执行耗时操作(如下载大文件),导致界面卡顿、无响应。
    • 解决:将耗时操作移到后台线程,仅通过 Dispatcher 传递结果到 UI 线程。
  3. Dispatcher 优先级问题

    • 问题:低优先级操作(如日志记录)可能被高优先级操作(如用户输入)阻塞。
    • 解决:通过 DispatcherPriority 控制优先级,例如:
      // 高优先级:优先更新进度
      Dispatcher.InvokeAsync(() => { progressBar.Value = 50; }, DispatcherPriority.Normal);
      // 低优先级:空闲时再执行日志
      Dispatcher.InvokeAsync(() => { LogToFile("进度50%"); }, DispatcherPriority.Background);
      

六、与其他技术的对比

  • WinForms:也有单线程 UI 模型,但线程检查较宽松(默认允许跨线程操作,仅抛出警告),而 WPF 强制禁止。
  • UWP/MAUI:线程模型类似 WPF,同样依赖 Dispatcher 实现线程间通信,但 API 略有差异(如 DispatcherQueue)。

总结

WPF 的线程模型核心是“单 UI 线程 + 多后台线程”,通过 Dispatcher 实现安全的线程间通信。关键原则是:

  • 耗时操作放后台线程,避免阻塞 UI。
  • UI 操作必须在 UI 线程执行,通过 Dispatcher 调度。

掌握这一模型是开发流畅、稳定的 WPF 应用的基础,尤其在处理串口通信、网络请求、大数据计算等场景时至关重要。

三、Dispatcher

在 WPF 中,Dispatcher 是处理线程与 UI 交互的核心机制,它确保所有 UI 操作都在创建 UI 元素的线程(通常是主线程) 上执行,避免跨线程操作导致的异常。下面详细介绍其用法和实例:

一、Dispatcher 的核心作用

WPF 控件具有线程亲和性:只有创建控件的线程(主线程)才能修改其属性(如 TextVisibility 等)。如果后台线程直接操作 UI,会抛出 InvalidOperationException

Dispatcher 的作用是:

  • 管理 UI 线程的工作项队列
  • 允许其他线程将 UI 操作“委托”给主线程执行
  • 控制操作的优先级

二、Dispatcher 的关键方法

方法说明
Invoke(Action)同步执行:阻塞当前线程,直到 UI 线程完成操作
BeginInvoke(Action)异步执行:不阻塞当前线程,操作加入队列后立即返回
InvokeAsync(Action)异步执行:返回 Task,支持 await(推荐)

三、使用场景与实例

以串口通信为例,后台线程接收数据后需要更新 UI 显示,这是 Dispatcher 的典型应用场景。

1. 基础用法:获取 Dispatcher 实例

通常在主线程(如窗口构造函数)中保存 Dispatcher 实例,供后台线程使用:

public partial class MainWindow : Window
{private Dispatcher _uiDispatcher;private SerialPort _serialPort;public MainWindow(){InitializeComponent();// 获取当前 UI 线程的 Dispatcher(主线程)_uiDispatcher = Dispatcher.CurrentDispatcher;}
}
2. 后台线程更新 UI(使用 InvokeAsync

假设串口数据接收在后台线程,需要将数据显示到 TextBox 中:

// 模拟后台线程接收串口数据
private void StartReceivingData()
{// 启动后台线程Task.Run(() =>{while (true){// 模拟接收数据(实际中是 _serialPort.Read())string receivedData = $"收到数据:{DateTime.Now:HH:mm:ss}\r\n";// 关键:通过 Dispatcher 将 UI 操作委托给主线程_uiDispatcher.InvokeAsync(() =>{// 这部分代码会在主线程执行,安全更新 UItxtReceivedData.AppendText(receivedData);// 滚动到最新内容txtReceivedData.ScrollToEnd();});// 模拟接收间隔Thread.Sleep(1000);}});
}
3. 带优先级的操作

Dispatcher 支持设置操作优先级(DispatcherPriority),高优先级的操作会先执行:

// 高优先级:立即更新状态文本
_uiDispatcher.InvokeAsync(() =>
{lblStatus.Text = "正在接收数据...";
}, DispatcherPriority.Normal);// 低优先级:耗时的日志记录(不会阻塞紧急 UI 更新)
_uiDispatcher.InvokeAsync(() =>
{LogToFile(receivedData);
}, DispatcherPriority.Background);

常见优先级(从高到低):

  • Send:立即执行(最高)
  • Normal:默认优先级
  • Background:低于正常 UI 操作
  • SystemIdle:系统空闲时执行(最低)
4. 同步执行(Invoke

如果需要等待 UI 操作完成后再继续(如弹窗确认),使用 Invoke

// 后台线程中需要用户确认
private void ShowConfirmation()
{bool? result = _uiDispatcher.Invoke(() =>{// 同步显示弹窗(会阻塞当前后台线程,直到用户点击)return MessageBox.Show("是否继续接收数据?", "确认", MessageBoxButton.YesNo);});if (result == false){// 停止接收逻辑}
}

四、注意事项

  1. 避免滥用 Invoke:同步执行会阻塞后台线程,可能导致性能问题,优先使用 InvokeAsync
  2. 不要在 UI 线程中调用 Dispatcher:主线程可以直接操作 UI,无需通过 Dispatcher
  3. 释放资源:后台线程退出时,需停止 Dispatcher 相关的循环操作,避免内存泄漏。
  4. 替代方案:在 MVVM 模式中,可使用 BindingOperations.EnableCollectionSynchronizationObservableCollection 的线程安全变体,但本质仍是基于 Dispatcher

总结

Dispatcher 是 WPF 中多线程与 UI 交互的“桥梁”,核心用法是通过 InvokeAsync(推荐)或 BeginInvoke 将后台线程的 UI 操作委托给主线程,确保界面安全更新。在串口通信、网络请求、定时任务等场景中必不可少。

四、WPF里的线程和进程

在WPF(Windows Presentation Foundation)中,线程和进程的基本概念与Windows系统一致(进程是程序运行的容器,线程是执行单元),但WPF对线程有特殊的UI线程约束,这是理解WPF线程模型的核心。

可以用“剧院演出”来类比:

1. WPF中的进程:就像“整个剧院”

  • 当你运行一个WPF程序(如一个桌面应用),Windows会为它创建一个独立进程。
  • 这个进程包含了程序所需的所有资源:代码、内存、窗口资源、UI控件(按钮、文本框等)的状态数据等,就像剧院包含舞台、道具、演员休息室等所有设施。
  • 进程间相互隔离,比如你同时打开两个WPF程序(如两个不同的记事本应用),它们是两个独立进程,一个崩溃不会影响另一个。

2. WPF中的线程:就像“剧院里的工作人员”

WPF程序的进程中至少有两个关键线程(可能更多):

(1)UI线程:“舞台总监”
  • 唯一负责UI操作:WPF规定,所有UI元素(按钮、窗口、动画等)的创建、更新、事件响应(如点击按钮)必须由同一个线程处理,这个线程就是UI线程。
  • 类比:就像舞台总监,所有舞台上的调度(演员上场、灯光变化、场景切换)必须经过他,别人不能直接指挥,否则会乱套。
  • 例子:当你在WPF窗口上点击一个按钮,按钮的Click事件只能在UI线程中处理;你想更新一个文本框的内容(TextBox.Text = "新内容"),也必须在UI线程中执行。
(2)后台线程:“后台工作人员”
  • 处理耗时任务:如果有耗时操作(如下载文件、计算大数据),不能放在UI线程中执行,否则会导致UI卡顿(就像舞台总监跑去搬道具,没人指挥舞台,演出会暂停)。
  • 类比:就像剧院里的灯光师、化妆师,他们在后台工作(不直接指挥舞台),但可以通过“消息”告诉舞台总监结果(比如“灯光已准备好”)。
  • 例子:在WPF中,你可以用TaskThread创建后台线程来下载图片,下载完成后,必须通过Dispatcher(WPF的线程通信工具)“通知”UI线程更新图片控件的显示。

关键区别:WPF线程 vs 普通Windows线程

普通Windows程序(如控制台应用)的线程可以随意操作资源,但WPF有严格的UI线程绑定

  • UI元素(如ButtonWindow)被“绑定”到创建它们的UI线程,其他线程不能直接修改它们。
  • 如果后台线程想更新UI,必须通过Dispatcher.InvokeDispatcher.BeginInvoke向UI线程“提交任务”,由UI线程处理。
举例:WPF中下载图片并显示
  1. 启动WPF程序,创建进程,同时创建UI线程(负责显示窗口和按钮)。
  2. 用户点击“下载图片”按钮:
    • 按钮的Click事件在UI线程中触发。
    • UI线程创建一个后台线程(避免卡顿),让它去下载图片(耗时操作)。
  3. 后台线程下载完成后,不能直接修改图片控件(Image.Source),而是通过Dispatcher告诉UI线程:“图片下载好了,你去更新显示吧”。
  4. UI线程收到消息后,在自己的执行队列中处理这个任务,最终更新图片显示。

总结

  • WPF的进程是程序运行的独立容器,包含所有资源,和系统进程概念一致。
  • WPF的线程中,UI线程是“特殊的”(唯一能操作UI),后台线程负责耗时任务,两者通过Dispatcher协作。

理解这个模型的核心是:WPF的UI元素是“单线程公寓”(STA),只能由创建它们的UI线程访问,这是避免UI混乱的关键设计。

五、UI线程的简单使用说明

在WPF中,更准确的说法是UI线程(属于应用程序进程的一部分)。每个WPF应用程序的进程中会有一个专门负责UI交互的线程,我们通常称之为“UI线程”。

一、UI线程的“样子”:它不是一个可见的实体,而是一种“执行角色”

UI线程是WPF进程启动时自动创建的线程,它的核心特征是:

  1. 负责所有UI元素的创建和更新:窗口、按钮、文本框等控件的初始化、属性修改、事件响应(如点击、输入)都必须在这个线程中执行。
  2. 拥有一个消息循环:不断接收和处理用户输入(如鼠标点击、键盘输入)、系统通知(如窗口大小变化),并刷新UI显示,就像一个“前台接待员”,时刻处理与用户的交互。
  3. 单线程特性:WPF的UI元素是“单线程公寓(STA)”模式,只能由创建它们的UI线程访问,其他线程不能直接操作。

二、如何“使用”UI线程?

在WPF开发中,我们不需要手动创建UI线程(框架会自动创建),但需要理解如何正确与UI线程交互,尤其是在涉及后台任务时。

1. 默认情况下:代码运行在UI线程中

当你在WPF的事件处理函数(如按钮点击)或初始化代码中操作UI时,代码默认就在UI线程中执行:

// 按钮点击事件(默认在UI线程中执行)
private void Button_Click(object sender, RoutedEventArgs e)
{// 直接修改文本框内容(安全,因为在UI线程中)MyTextBox.Text = "按钮被点击了";
}
2. 后台线程如何与UI线程通信?

如果有耗时操作(如下载、计算),需要放在后台线程执行,完成后再通知UI线程更新界面。这时必须通过WPF的Dispatcher(UI线程的“消息调度器”)来实现:

步骤示例

private void StartLongTaskButton_Click(object sender, RoutedEventArgs e)
{// 1. 在UI线程中启动一个后台线程(避免阻塞UI)Task.Run(() => {// 这部分代码在后台线程执行(耗时操作)Thread.Sleep(3000); // 模拟耗时任务(如下载文件)string result = "任务完成!";// 2. 后台线程不能直接更新UI,需通过Dispatcher通知UI线程MyTextBox.Dispatcher.Invoke(() => {// 这部分代码由Dispatcher调度到UI线程执行MyTextBox.Text = result;});});
}

关键说明

  • Dispatcher是UI线程的“代理”,每个UI元素(如MyTextBox)都能通过Dispatcher属性访问到UI线程的调度器。
  • Invoke:同步等待UI线程执行任务(会阻塞后台线程,直到UI更新完成)。
  • BeginInvoke:异步让UI线程执行任务(不阻塞后台线程,更常用)。
3. 如何判断当前线程是否是UI线程?

可以通过Dispatcher.CheckAccess()方法判断:

if (MyTextBox.Dispatcher.CheckAccess())
{// 当前在UI线程中,可直接操作UIMyTextBox.Text = "在UI线程中";
}
else
{// 不在UI线程中,需通过DispatcherMyTextBox.Dispatcher.BeginInvoke(() => {MyTextBox.Text = "通过Dispatcher更新";});
}

三、错误示例:后台线程直接操作UI(会崩溃)

如果后台线程直接修改UI元素,WPF会抛出异常(跨线程操作无效):

// 错误示例!会导致程序崩溃
private void BadButton_Click(object sender, RoutedEventArgs e)
{Task.Run(() => {// 后台线程直接修改UI(禁止!)MyTextBox.Text = "这会报错!"; });
}

总结

  • UI线程是WPF进程中自动创建的“UI管家”,负责所有界面相关操作。
  • 日常开发中,大部分UI操作(如事件处理、初始化)默认就在UI线程中,无需额外处理。
  • 后台线程与UI交互必须通过Dispatcher,这是WPF线程模型的核心规则,遵守它才能避免界面卡顿或崩溃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93286.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA知识点(四):SpringBoot与分布式、微服务架构

文章目录SpringBoot 使用 Validation 进行参数校验并统一返回校验异常引入相应的依赖Validation的基本校验注解添加参数校验在DTO的属性上添加校验在controller对应的DTO添加Valid或者Validated对于复杂String校验我们可以使用正则来校验&#xff0c;如下所示&#xff1a;自定义…

GPU 服务器ecc报错处理

1. 常见原因分析内存硬件问题&#xff1a;DIMM 内存模块损坏或接触不良&#xff08;最常见原因&#xff09;。内存插槽氧化、松动或物理损坏。内存与主板兼容性问题&#xff08;尤其是非原厂内存&#xff09;。环境因素&#xff1a;服务器内部温度过高&#xff0c;导致内存稳定…

STM32入门之通用定时器PWM

一、通用定时器简介STM32通用定时器由一个通过可编程预分频器驱动的16位自动重装载计数器组成&#xff0c;适用于多种应用场景&#xff0c;包括测量输入信号的脉冲长度&#xff08;利用输入捕获功能&#xff09;和生成输出波形&#xff08;使用输出比较及PWM功能&#xff09;。…

第十八节 MATLAB for循环

MATLAB中 for 循环是一个重复的控制结构&#xff0c;可以有效地写一个循环&#xff0c;只是执行的次数是特定的。MATLAB for 循环语法:MATLAB中的 for循环的语法如下&#xff1a;for index values<program statements>... endfor 循环的值有下述三种形式之一&#xff1a…

嵌入式硬件篇---zigbee无线串口通信问题解决方法

针对 ZigBee 无线串口通信中接收异常的问题&#xff0c;需结合其射频特性、网络机制、硬件配置等多维度原因&#xff0c;采取针对性解决措施。以下从具体场景出发&#xff0c;提供可落地的解决方法&#xff1a;一、解决射频层干扰与信号衰减问题射频层是无线通信的基础&#xf…

移动高清盒子6PRO-河南创维E900V22D-晶晨S905L3B-4+16G-安卓9-线刷固件包

移动高清盒子6PRO-河南创维E900V22D-晶晨S905L3B-416G-安卓9-线刷固件包线刷方法&#xff1a;1、准备好一根双公头USB线刷刷机线&#xff0c;长度30-50CM长度最佳&#xff0c;同时准备一台电脑&#xff1b;2、电脑上安装好刷机工具Amlogic USB Burning Tool 软件 →打开软件 →…

台式电脑有多个风扇开机只有部分转动的原因

一、风扇未连接或连接松动这是最常见的原因之一&#xff0c;台式机风扇通常需要通过线材与主板或电源连接&#xff1a;主板接口问题&#xff1a;CPU 风扇、机箱风扇等多连接到主板的风扇接口&#xff08;如 CPU_FAN、SYS_FAN&#xff09;&#xff0c;若线材未插紧、插错接口&am…

【测试报告】思绪网(Java+Selenium+Jmeter自动化测试)

一、项目简介思绪网作为一种在线交流平台&#xff0c;支持用户在平台下发布文章&#xff0c;并进行讨论。主要由登录页面&#xff0c;论坛页面&#xff0c;帖子编辑页&#xff0c;帖子详情页等页面组成。二、项目功能1.登录页面&#xff1a;输入正确的账号密码进行登录,跳转博客…

Nestjs框架: 基于Mongodb的多租户功能集成和优化

概述 基于前文&#xff0c;我们知道如何集成多租户的相关功能了, 现在我们继续集成Monodb的多租户形式需要注意的是&#xff0c;MongoDB 在 NestJS 中的使用过程中存在一些“坑点”如果按照默认方式集成&#xff0c;会发现连接数在不断增长&#xff0c;即使我们请求的是相同的数…

如何利用机器学习分析筛选生物标记物

在生物信息学中&#xff0c;Lasso回归、随机森林&#xff08;Random Forest&#xff09;和XGBoost因其各自的特性和优势&#xff0c;被广泛应用于基因组学、蛋白质组学、药物发现和疾病机制研究等领域。 Lasso回归 癌症亚型分类&#xff1a;从TCGA数据中筛选驱动基因&#xf…

计算机网络(基础篇)

TCP/IP 网络模型 应用层&#xff08;Application Layer&#xff09; 应用层只需要专注于为用户提供应用功能&#xff0c;比如 HTTP、FTP、Telnet、DNS、SMTP等。应用层是工作在操作系统中的用户态&#xff0c;传输层及以下则工作在内核态。传输层&#xff08;Transport Layer&a…

全面解析 CSS Flex 布局:从入门到精通的所有属性详解

1. Flex 容器属性 通过 display: flex 或 display: inline-flex 将元素设置为 Flex 容器。以下是所有容器属性。 1.1 display: flex | inline-flex 作用&#xff1a;定义一个 Flex 容器。可选值&#xff1a; flex&#xff1a;块级容器&#xff0c;占据整行。inline-flex&#x…

数据结构:对角矩阵(Diagonal Matrix)

目录 矩阵的传统表示&#xff1a;二维数组 &#x1f50d; 真正有用的数据是哪些&#xff1f; 从二维数组转为一维数组 用 C 类实现对角矩阵 1. 对角矩阵真正需要存什么&#xff1f; 2. 对角矩阵允许哪些行为&#xff1f; 3. 为什么要动态分配数组&#xff1f; 接下来推…

Leetcode_349.两个数组的交集

这道题的意思很明确&#xff0c;就是让寻找两个数组中的共同元素&#xff0c;并去重&#xff0c;由此可以联想到哈希表的特性&#xff0c;注意到题目给的数据范围&#xff0c;在1000以内&#xff0c;所以本题可以使用 STL 的库函数&#xff0c;也可以使用数组进行模拟。 本题要…

STM32——寄存器映射

总 &#xff1a;STM32——HAL库总结-CSDN博客 芯片资料&#xff1a; STM32F1系列参考手册-V10&#xff08;中&#xff09; STM32F103ZET6(English) 一、寄存器基础 1.1 简介 单片机内部的控制机构。 像空气开关控制电路一样的原理&#xff0c;打开关闭某个开关&#xff0…

Java响应式编程

Java 响应式编程是一种基于异步数据流处理的编程范式&#xff0c;它强调数据流的声明式构建和传播变化的自动响应。Java 9 引入的Flow API为响应式编程提供了标准接口&#xff0c;而 Reactor 和 RxJava 等第三方库则提供了更丰富的操作符和工具。核心概念Publisher&#xff08;…

【重学数据结构】二叉搜索树 Binary Search Tree

目录 二叉搜索树的数据结构 手写实现二叉搜索树 树节点定义 插入节点 源码 流程图 二叉树插入步骤图解 第一步: 插入 20 第二步: 插入 10 第三步: 插入 30 第四步: 插入 5 查找节点 源码 场景一: 查找成功 (search for 25) 第一步: 从根节点开始 第二步:…

四、计算机组成原理——第1章:计算机系统概述

目录 1.1计算机发展历程 1.1.1计算机硬件的发展 1.计算机的四代变化 2.计算机元件的更新换代 1.1.2计算机软件的发展 1.2计算机系统层次结构 1.2.1计算机系统的组成 1.2.2计算机硬件 1.冯诺依曼机基本思想 2.计算机的功能部件 (1)输入设备 (2)输出设备 (3)存储器 (4)运算器 (5)…

flutter TextField 失去焦点事件

在 Flutter 中&#xff0c;处理 TextField 的失去焦点事件&#xff08;即失去焦点时触发的操作&#xff09;通常有两种常用方式&#xff1a;使用 FocusNode 或 onEditingComplete 回调。以下是具体实现&#xff1a; import package:flutter/material.dart;class MyTextField e…

Moonlight for ChromeOS 常见问题解决方案

Moonlight for ChromeOS 常见问题解决方案 项目基础介绍 Moonlight for ChromeOS 是一个开源的 NVIDIA GameStream 客户端&#xff0c;允许用户将他们的游戏从高性能的桌面电脑流式传输到运行 ChromeOS 的设备上。该项目还支持 Android 和 iOS/tvOS 平台。Moonlight for Chrome…