Linux笔记---线程
1. 线程的介绍
1.1 线程的概念
基本定义: 线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程(Process)之中(或者说是进程的一部分、对进程的划分),是进程中的实际运作单位。
- 把进程想象成一个工厂车间。这个车间有自己的厂房(地址空间)、原材料仓库(内存数据)、生产设备(CPU时间)、规章制度(权限)等资源。
- 把线程想象成这个工厂车间里的工人。一个车间(进程)可以有一个或多个工人(线程)。这些工人共享车间的所有资源(厂房、仓库、设备、制度),但他们各自独立地执行不同的具体任务(如搬运、组装、质检)。
核心特征:
属于进程: 一个线程必须存在于某个进程中。进程是资源分配的基本单位,线程是CPU调度的基本单位。
共享资源: 同一个进程内的所有线程共享该进程所拥有的全部资源,包括:
- 地址空间(内存): 代码段、数据段、堆、全局变量、静态变量、打开的文件描述符等。
- 环境: 当前工作目录、用户ID、组ID、进程权限等。
私有资源: 每个线程也有自己独有的资源,用于维持其独立执行的能力:
- 线程ID: 唯一标识。
- 寄存器组: 程序计数器(PC)、栈指针(SP)等,用于保存执行现场。
- 栈: 用于存储局部变量、函数调用参数和返回地址。每个线程有自己的栈空间。
- 错误码: errno(某些系统下)。
- 信号掩码:
- 优先级: (如果操作系统支持线程优先级调度)。
执行: 线程是程序执行流的最小单元。一个标准的单线程程序只有一个执行流(主线程)。多线程程序则在一个进程内有多个独立的执行流并发或并行地运行。
1.2 为什么要引入线程
引入线程主要是为了解决传统进程模型在并发编程和资源利用效率上的一些局限性:
更轻量级的并发:
- 创建/销毁开销小: 创建或终止一个线程比创建一个新进程快得多,因为线程共享其所属进程的资源(如地址空间、文件描述符),操作系统需要分配和初始化的资源(主要是栈和寄存器)远少于创建一个全新的进程。
- 切换开销小: 在同一进程内切换线程(上下文切换)比在不同进程间切换(进程上下文切换)开销小得多。因为线程共享地址空间和大部分资源,切换时只需保存和恢复少量私有寄存器状态(PC, SP, 寄存器等),无需切换内存映射表(如页表)、刷新TLB等耗时操作。这使得线程间切换非常高效。
- 结论: 线程是实现并发编程的一种更轻量、更高效的方式,特别适合需要频繁创建和销毁执行单元或需要快速响应的场景(如Web服务器处理大量并发请求)。
提高资源利用率与系统吞吐量:
- 充分利用多核CPU: 现代计算机普遍拥有多核CPU。多线程允许一个进程内的多个线程真正并行地在不同CPU核心上同时运行,极大地提高了计算密集型任务的执行速度和CPU利用率。单进程单线程只能利用一个核心。
- 重叠I/O与计算: 当一个线程因等待I/O操作(如读写磁盘、网络通信)而阻塞时,同一个进程内的其他线程可以继续运行,利用CPU进行计算。这避免了整个进程被阻塞,提高了CPU和I/O设备的整体利用率和系统吞吐量。例如,一个GUI程序可以用一个线程处理用户界面交互,另一个线程执行后台计算,保证界面不卡顿。
简化通信与数据共享:
- 天然共享内存: 由于同一进程内的线程共享地址空间(堆、全局变量等),它们之间的通信变得极其简单和快速,直接通过读写共享内存即可实现,无需像进程间通信(IPC)那样使用管道、消息队列、共享内存(需显式设置)、套接字等复杂且相对较慢的机制。
- 简化程序设计: 对于需要紧密协作、频繁交换大量数据的任务,使用多线程比使用多进程+IPC在程序设计上通常更直观、代码更简洁(尽管引入了同步的复杂性)。
提高响应性:
- 在交互式应用中(如GUI、游戏、服务器),将耗时操作(如网络请求、复杂计算)放在单独的线程中执行,可以保证主线程(如UI线程)保持响应,及时处理用户输入或更新界面,避免程序“假死”,提升用户体验。
总结引入线程的原因: 为了在保持进程提供的资源隔离和安全性的同时,提供一种更轻量、高效、易于共享数据的并发执行机制,从而更好地利用多核处理器、提高系统资源利用率(CPU、I/O)、提升程序响应速度和系统吞吐量。
1.3 线程vs进程
- 资源 vs 执行: 进程是资源分配的容器;线程是执行调度的实体。
- 隔离 vs 共享: 进程间高度隔离;线程间高度共享(同一进程内)。
- 开销: 进程创建/销毁/切换开销大;线程开销小。
- 通信: 进程间通信复杂且慢(IPC);线程间通信简单且快(共享内存),但必须同步。
- 崩溃影响: 进程崩溃不影响其他进程;线程崩溃很可能导致整个进程崩溃。
- 并行利用: 多线程能充分利用单机多核进行并行计算(线程数量不宜超过处理器数量)。
特性 | 进程 (Process) | 线程 (Thread) |
基本定义 | 资源分配的基本单位。拥有独立地址空间和系统资源。 | 共享其所属进程的所有资源(地址空间、文件描述符、环境等)。拥有私有栈、寄存器、线程ID、错误状态、信号掩码、优先级。 |
资源所有权 | 拥有独立的地址空间、文件描述符表、信号处理、环境变量等系统资源。 | 共享其所属进程的所有资源(地址空间、文件描述符、环境等)。拥有私有栈、寄存器、线程ID、错误状态、信号掩码、优先级。 |
创建/销毁开销 | 大。需要分配和初始化独立的地址空间、页表、资源表等。 | 小。主要分配栈和少量寄存器状态,共享进程资源。 |
切换开销 | 大 (进程上下文切换)。需要切换地址空间(页表、TLB刷新)、CPU状态、内核栈等。 | 小 (线程上下文切换)。只需切换私有寄存器、栈指针等,共享地址空间不变。 |
通信方式 | 复杂且慢。必须使用操作系统提供的IPC机制:管道、消息队列、共享内存(需显式管理)、信号量、套接字等。 | 简单且快。天然共享进程内存(全局变量、堆)。直接读写即可通信。但需同步机制(互斥锁、信号量等)保护共享数据。 |
健壮性 | 高。一个进程崩溃(如段错误)通常不会直接影响其他进程(地址空间隔离)。 | 低。一个线程崩溃(如非法内存访问)可能导致整个进程终止,因为共享地址空间,破坏共享数据会波及其他线程。 |
独立性/隔离性 | 高。进程间有严格的地址空间隔离和资源保护。 | 低。线程间共享大部分资源,隔离性弱。 |
并发性 | 进程间可以并发或并行执行(多进程编程)。 | 线程间可以并发或并行执行(多线程编程)。使得进程内部出现多个可并发执行的执行流。 |
系统资源占用 | 多。每个进程都有独立的内存映像、内核数据结构(PCB)等。 | 少。多个线程共享一个进程的资源,额外开销主要是私有栈和线程控制块(TCB)。 |
适用场景 | 需要高隔离性、高安全性的任务(如不同用户的程序、关键服务)。需要利用多机并行(分布式)。 | 需要高效并发、紧密协作、频繁数据共享的任务(如计算密集型并行、I/O密集型服务器、GUI响应)。需要充分利用单机多核。 |
1.4 线程的实现方式
内核支持线程(Kernel-Level Threads, KLT)和用户级线程(User-Level Threads, ULT)是两种不同的线程实现和管理方式。
1.4.1 内核支持线程vs用户级线程
特性 | 内核支持线程 (KLT) | 用户级线程 (ULT) |
管理主体 | 操作系统内核 (OS Kernel) | 用户空间线程库 (Runtime Library / Thread Library) |
内核感知 | 内核知道每个KLT的存在,并直接调度它们。 | 内核不知道ULT的存在。它只看到并调度承载ULT的进程(单个KLT)。 |
实现位置 | 在内核空间实现,需要内核支持(系统调用)。 | 在用户空间实现,完全由用户级库管理(如POSIX的pthreads库 通常实现为KLT,但像早期的Java“绿色线程”、GNU Pth是ULT)。 |
线程控制块 (TCB) | 存放在内核空间 (Kernel Space)。 | 存放在用户空间 (User Space)。 |
创建/销毁/切换 | 需要陷入内核态(系统调用),开销相对较大。 | 完全在用户态进行(库函数调用),开销极小(类似函数调用)。 |
调度 | 内核负责调度。内核调度器决定哪个KLT获得CPU时间。 | 用户级线程库负责调度。库的调度器决定进程内哪个ULT获得CPU时间。内核只调度该进程对应的那个KLT。 |
阻塞影响 | 一个KLT阻塞(如I/O)时,内核可以调度同一进程内的另一个KLT或不同进程的KLT运行。不会阻塞整个进程。 | 一个ULT阻塞(如I/O)时,由于内核只看到进程阻塞,会阻塞整个进程(即承载它的那个KLT),导致该进程内的所有ULT都无法执行。 |
利用多处理器 (SMP) | 良好支持。内核可以将同一进程的不同KLT分配到不同的CPU核心上真正并行执行。 | 不支持(纯ULT模型)。因为内核只把一个进程(对应一个KLT)调度到一个核心上,该进程内的所有ULT只能在该核心上并发(交替执行),无法并行。 |
性能 | 创建/销毁/切换开销较大,但能更好地利用多核和避免I/O阻塞导致的进程停顿。 | 创建/销毁/切换开销极小,但无法利用多核,且一个ULT阻塞会导致整个进程(所有ULT)阻塞。 |
健壮性 | 相对较高。内核管理,一个线程崩溃通常不影响整个系统。 | 依赖于线程库实现。线程库崩溃可能导致整个进程崩溃。 |
灵活性 | 由内核策略决定,用户控制相对较弱。 | 用户级线程库可以定制自己的调度策略(如优先级、轮转),灵活性高。 |
例子 | 现代操作系统的主流线程实现: - Windows 线程 - Linux POSIX线程 (pthreads) - macOS POSIX线程 (pthreads) | 历史上的/特定语言的实现: - GNU Portable Threads (Pth) - 早期Java的“绿色线程” (Green Threads) - Python的greenlet(需配合事件循环) - 一些协程库(Coroutine Libraries) |
1.4.1 混合模型:两级模型 (Many-to-Many)
为了结合KLT和ULT的优点,克服各自的缺点,现代操作系统和线程库普遍采用混合模型(也称为两级模型,Many-to-Many Model)。
原理:
- 用户程序创建和管理的是用户级线程 (ULT)。
- 用户级线程库将这些ULT映射(绑定)到一组内核支持线程 (KLT) 上执行。
- 内核只看到并调度这些KLT。
- ULT库负责将ULT调度到可用的KLT上运行。
优点:
- 开销可控: ULT的创建/销毁/切换开销小(用户态)。
- 避免阻塞: 如果一个ULT在KLT上阻塞(如I/O),内核只会阻塞那个KLT。库可以将该ULT从阻塞的KLT上解除绑定,并把其他就绪的ULT调度到进程内其他未阻塞的KLT上继续执行。整个进程不会被阻塞。
- 利用多核: 库可以将ULT映射到多个KLT上,内核可以将这些KLT调度到不同的CPU核心上并行执行。
- 灵活性: ULT库可以有自己的调度策略。
2. Linux当中的线程
在Linux当中,我们可以使用pthread库来进行多线程编程。
pthread库是 POSIX 线程标准的实现,在Linux上,最主要的实现是 NPTL (Native POSIX Threads Library),是 glibc (GNU C Library) 核心且不可或缺的一部分。
pthread库提供的是内核支持线程还是用户级线程呢?
实际上,在Linux当中,pthread库采用的是混合模型来实现线程,在用户空间上提供线程的概念,而在内核层面上将用户线程1 : 1绑定到轻量级进程(线程)。
在很多操作系统的教科书当中都会说明,线程又叫做轻量级进程,从其概念上就可以很好地理解这样命名的原因。
但是在Linux当中,这样的命名可不只是因为形象,而是因为Linux内核当中轻量级进程确实是一种特殊的进程。
实际上,在Linux内核当中,只有一种运行实体,那就是task_struct(也就是说Linux中只有PCB而不存在TCB)。轻量级进程就是与主进程共享全局资源的进程。
2.1 轻量级进程(LWP)
2.1.1 概念
轻量级进程本质上是 Linux 内核调度和管理的线程(Thread)。 它是 Linux 内核线程实现的具体表现形式。
- 核心特性:
- 共享资源: 多个 LWP(属于同一个进程)共享其父进程的:虚拟地址空间、文件描述符表、信号处理程序、环境变量、用户/组 ID (UID/GID)。
- 共享资源: 多个 LWP(属于同一个进程)共享其父进程的:虚拟地址空间、文件描述符表、信号处理程序、环境变量、用户/组 ID (UID/GID)。
- 独立的执行状态: 每个 LWP 拥有自己独立的:
- 线程 ID (TID) - 在同一个进程内唯一,在系统内也唯一(Linux 中线程和进程使用相同的 ID 命名空间,TID 其实就是内核视角的 PID)。
- 程序计数器 (PC)
- 寄存器集 (Registers)
- 栈 (Stack) - 每个线程有自己的栈空间(在进程的地址空间内分配)。
- 信号掩码 (Signal Mask)
- 线程特定数据 (Thread-Local Storage - TLS)
- 调度优先级和策略(部分可独立设置)
- “轻量级”的含义:
- 创建开销小: 创建一个新的 LWP(通过 clone() 系统调用,并指定共享资源的标志,如 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)不需要复制父进程的地址空间等主要资源,只需设置独立的执行栈和上下文,因此比创建完整进程快得多。
- 切换开销小: 同一个进程内的 LWP 切换,因为共享地址空间(TLB 缓存无需完全刷新)、文件表等,上下文切换通常比进程间切换快。
- 通信开销小: 共享地址空间的 LWP 之间通信极其高效,可以直接读写共享内存区域(全局变量、堆内存),仅需注意同步问题(互斥锁、信号量等)。
- 内核可见: LWP 是内核直接知晓并调度的实体。内核调度器看到的是一个个 LWP,并根据它们的调度策略和优先级进行调度。
- 调度单位: LWP 是 Linux 内核进行 CPU 调度的基本单位。 当我们说“内核调度进程”时,实际上更精确地说,内核是在调度该进程内的一个或多个 LWP。
2.1.2 关键点:LWP 就是 Linux 的线程
- 在 Linux 中,当你在用户空间使用 POSIX 线程库 (pthreads) 创建线程时 (pthread_create),底层正是通过 clone() 系统调用创建了一个新的 LWP。
- 一个传统的“单线程进程”实际上就是由一个 LWP 构成的进程。
- 一个“多线程进程”则是由多个共享资源的 LWP 组成的。
- ps -aL 命令可以查看系统当中的线程。
$ ps -aL | head -1 && ps -aL | grep mythread PID LWP TTY TIME CMD 2711838 2711838 pts/235 00:00:00 mythread 2711838 2711839 pts/235 00:00:00 mythread -L 选项:打印线程信息
2.1.3 历史背景与术语演变
- LinuxThreads: Linux 早期使用一个名为 LinuxThreads 的线程库。在这个模型中,每个用户线程对应一个内核 LWP。然而,它存在一些问题,比如信号处理不完美、管理线程效率低、不符合 POSIX 标准(例如,所有线程有不同 PID)等。此时,“LWP”这个术语被广泛使用来指代内核线程。
- NPTL (Native POSIX Thread Library): 为了克服 LinuxThreads 的缺点,引入了 NPTL(集成在 glibc 中)。NPTL 极大地提高了 Linux 线程的性能和 POSIX 兼容性。在 NPTL 中:
- 用户线程仍然通过 LWP(内核线程)实现。
- 但引入了更高效的同步原语(Futex)。
- 实现了线程组的概念,同一个进程的所有线程共享一个 PID(getpid() 返回相同值),通过 TID 区分线程(gettid())。
- 信号处理更符合 POSIX 标准。
- 现代术语: 在现代 Linux 文档和讨论中:
- “线程” (Thread) 是最常用和最标准的术语,指代用户空间的可调度执行流。
- “内核线程” (Kernel Thread) 指在内核空间运行、没有用户空间上下文的后台任务(如 kworker, ksoftirqd)。
- “轻量级进程 (LWP)” 这个术语逐渐淡化,主要用于描述用户线程在内核中的具体实现实体。在讨论内核调度细节或查看 /proc 文件系统(如 /proc/[pid]/task/[tid]/)时可能还会遇到。ps/top 等工具也常用 LWP 列名显示线程 ID (TID)。
相关文章:

Linux笔记---线程
1. 线程的介绍 1.1 线程的概念 基本定义: 线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程(Process)之中(或者说是进程的一部分、对进程的划分),是进程中的实际…...

MCP架构深度解析:从基础原理到核心设计
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…...
【监控】pushgateway中间服务组件
Pushgateway 是 Prometheus 生态中的一个中间服务组件,以独立工具形式存在,主要用于解决 Prometheus 无法直接获取监控指标的场景,弥补其定时拉取(pull)模式的不足。 其用途如下: 突破网络限制࿱…...

数据库暴露--Get型注入攻击
1.背景知识 1.1Post、Get的对比 特性GET 方法POST 方法HTTP 方法类型GETPOST数据位置URL 查询字符串(?key=value)请求体(Request Body)数据可见性明文显示在 URL 和浏览器历史中不可见(除非开发者工具查看)数据长度限制受 URL 长度限制(通常约 2048 字符)无明确限制(…...

AI炼丹日志-26 - crawl4ai 专为 AI 打造的爬虫爬取库 上手指南
点一下关注吧!!!非常感谢!!持续更新!!! Java篇: MyBatis 更新完毕目前开始更新 Spring,一起深入浅出! 大数据篇 300: Hadoop&…...

ESP32-idf学习(四)esp32C3驱动lcd
一、前言 屏幕是人机交互的重要媒介,而且现在我们产品升级的趋势越来越高大尚,不少产品都会用lcd来做界面,而esp32c3在一些项目上是可以替代主mcu,所以驱动lcd也是必须学会的啦 我新买的这块st7789,突然发现是带触摸…...

【python】uv管理器
uv是一个速度极快的 Python 包和项目管理器,用 Rust 编写。 安装 安装uv之前,确保你的电脑不需要安装了python 在Windows下,可以使用官方的脚本直接安装 powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.…...
关于Web安全:7. WebShell 管理与持久化后门
一、菜刀马 菜刀马(ChinaZ WebShell) 是一种与“中国菜刀(ChinaZ)”客户端配合使用的 WebShell 木马,广泛应用于 Web 渗透测试中,主要使用 PHP/ASP/JSP 等语言编写。 它的本质是一个一句话木马࿰…...
音视频中的复用器
🎬 什么是复用器(Muxer)? 复用器(muxer)是负责把音频、视频、字幕等多个媒体流打包(封装)成一个单一的文件格式的组件。 💡 举个形象的例子: 假设你有两样东…...

戴尔AI服务器订单激增至121亿美元,但传统业务承压
戴尔科技121亿美元的AI服务器订单,不仅超过了公司整个2025财年的AI服务器出货量,更让其AI订单积压达到144亿美元的历史高位。 戴尔科技最新财报显示,AI服务器需求的爆炸式增长正在重塑这家老牌PC制造商的业务格局,但同时也暴露出…...
远程线程注入
注入简单来说就是让别人的程序执行 你想要让他执行的dll #include<iostream> #include<Windows.h> using namespace std;char szBuffer[] "C:\\Users\\20622\\source\\repos\\Dll1\\Debug\\test.dll"; //dll路径void RemoteThreadInject(DWORD Pid,PCH…...

如何手搓扫雷(待扩展)
文章目录 一、扫雷游戏分析与设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析1.2.2 文件结构设计 二、扫雷游戏的代码实现三、扫雷游戏的扩展总结 一、扫雷游戏分析与设计 扫雷游戏网页版 1.1 扫雷游戏的功能说明 使用控制台(黑框框的程序&a…...

俄军操作系统 Astra Linux 安装教程
安装 U盘制作 Rufus 写盘工具:https://rufus.ie/ Astra Linux ISO 镜像文件:https://dl.astralinux.ru/astra/stable/2.12_x86-64/iso/ 准备一个8g以上的u盘,打开Rufus写盘工具,选择下载的iso镜像,写入u盘ÿ…...

第三方软件评测机构如何助力软件品质提升及企业发展?
第三方软件评测机构与软件开发者及使用者无直接关联,它们提供全方位的检测和公正的评价服务。这样的评测可以展现客观的成效,对提升软件的品质具有显著影响,且在软件产业中发挥着至关重要的角色。 评测的客观性 独立第三方机构与软件开发者…...

Python打卡训练营Day40
DAY 40 训练和测试的规范写法 知识点回顾: 彩色和灰度图片测试和训练的规范写法:封装在函数中展平操作:除第一个维度batchsize外全部展平dropout操作:训练阶段随机丢弃神经元,测试阶段eval模式关闭dropout 作业&#x…...
【仿生系统】爱丽丝机器人的设想(可行性优先级较高)
非程序化、能够根据环境和交互动态产生情感和思想,并以微妙、高级的方式表达出来的能力 我们不想要一个“假”的智能,一个仅仅通过if-else逻辑或者简单prompt来模拟情感的机器人。您追求的是一种更深层次的、能够学习、成长,并形成独特“个性…...

JS逆向案例—喜马拉雅xm-sign详情页爬取
JS逆向案例——喜马拉雅xm-sign详情页爬取 声明网站流程分析总结 声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权&am…...
钩子函数的作用(register_hook)
钩子函数仅在backward()时才会触发。其中,钩子函数接受梯度作为输入,返回操作后的梯度,操作后的梯度必须要输入的梯度同类型、同形状,否则报错。 主要功能包括: 监控当前的梯度(不返回值)&…...
电子电路:深入了解CMOS技术构造和工作原理
一、CMOS的基本结构与工作原理 1. 核心结构:互补MOSFET CMOS(互补金属氧化物半导体)的核心是成对的NMOS(N沟道MOSFET)和PMOS(P沟道MOSFET)晶体管,两者共享同一硅衬底但通过阱(Well) 隔离: NMOS:构建在P型衬底上,源/漏极为N⁺掺杂区。当栅极电压(V_GS)高于阈值…...

STM32CubeMX定时器配置
STM32CubeMX定时器配置 一,Mode界面1,Slave Mode (从模式)2,Trigger Source (触发源) 三,Channelx(通道模式)1,Input Capture2,Output Compare3,PWM Generation4…...

QNAP MEMOS 域名访问 SSL(Lucky)
注意:下述是通过ssh、docker-compose方式安装docker的,不是直接在container station中安装的哈!!! 一、编辑docker-compose.yml文件 用“#”号标识的,在保存文件的时候建议去掉,不然有时候会出…...
跟单业务并发量分析
虚拟货币交易所中的跟单交易(copy trading)业务在高峰期的确可能产生较高的并发量,但具体并发量取决于多个因素,包括交易所的规模、用户数量、热门交易员的活跃度、行情波动频率等。 📌 1. 跟单交易的并发特点 触发集…...

如何将多张图组合到一张图里同时保留高的分辨率(用PPT+AdobeAcrobat)
文章目录 一、用PPT排版得到一页排布了很多图片的PPT二、用AdobeAcrobat打开pdf文件三、最后得到的图片 一、用PPT排版得到一页排布了很多图片的PPT 步骤如下 ①将幻灯片大小的长设置为17.2,宽根据图像多少进行调整,我这里是10 幻灯片大小的长设置步骤&…...

pycharm找不到高版本conda问题
pycharm找不到高版本conda问题 高版本的condaPycharm不能自动识别,需要手动添加。 首先打开你要添加的conda环境win的话在conda终端输入 where conda查找conda的可执行文件位置 进入Pycharm设置,点击添加解释器,点击加载环境,…...
支持selenium的chrome driver更新到137.0.7151.55
最近chrome释放新版本:137.0.7151.55 如果运行selenium自动化测试出现以下问题,是需要升级chromedriver才可以解决的。 selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only su…...

2025年上半年软考系统架构设计师--案例分析试题与答案
必选题一:大模型训练系统 某公司开发一个在线大模型训练平台,支持 Python 代码编写、模型训练和部署,用户通过 python 编写模型代码,将代码交给系统进行模型代码的解析,最终由系统匹配相应的计算机资源进行输出,用户不需要关心底层硬件平台。 a.系统发生…...

Eclipse 插件开发 5.2 编辑器 获取当前编辑器
Eclipse 插件开发 5.2 编辑器 获取当前编辑器 1 获取活跃编辑器2 获取全部编辑器 Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Click1 Bundle-SymbolicName: com.xu.click1;singleton:true Bundle-Version: 1.0.0 Bundle-Activator: com.xu.click1.Activato…...
讲述我的plc自学之路 第十二章
“老k,你没想过自己以后怎么过吗?”lora听我夸他漂亮,开始鼓起勇气追问我的过往。 “我还能怎样呢,说实话,家里介绍过几次相亲了,上来就问车问房的,大多数不了了之。”我解释道。 “老k这你就…...

Visual Studio 的下载安装
下载 官网:https://visualstudio.microsoft.com/zh-hans/ 点击免费 Visual Studio。 点击 Visual Studio Community 下的免费下载。 保留并下载。 安装 双击下载的 exe 安装文件,点击继续。 等他下载安装完。 选择你要下载的组件(我只勾了一个 .NET 桌…...
C# 如何获取当前成员函数的函数名
C# 如何获取当前成员函数的函数名 在 C# 中获取当前成员函数的名称,有以下几种常用方法: 1. 使用 MethodBase.GetCurrentMethod()(反射) using System.Reflection;public void MyMethod() {string methodName MethodBase.GetCu…...