Linux 進程調度與管理:從內核管理到調度機制的深度解析

文章目錄

  • 引言
  • 一、進程基礎:概念與核心數據結構
    • 1.1 進程的本質:程序的動態化身
    • 1.2 進程控制塊(PCB):內核管理的靈魂
      • 1.2.1 鏈表節點嵌入
      • 1.2.2 鏈表操作宏
      • 1.2.3 全局鏈表管理
    • 1.3 進程查看與系統調用
      • 1.3.1 通過系統調用獲取進程標識符
      • 1.3.2 通過系統調用創建子進程
  • 二、進程生命周期:狀態與特殊場景
    • 2.1 進程的幾個狀態
    • 2.2 進程狀態查看
    • 2.3 僵尸進程與孤兒進程:資源管理的兩面性
      • 2.3.1 僵尸進程
        • a. 什么是僵尸進程?
        • b. 僵尸進程的成因
        • c. 僵尸進程的危害
        • d. 如何識別僵尸進程?
      • 2.3.2 孤兒進程
        • a. 什么是孤兒進程?
        • b. 孤兒進程與僵尸進程的對比
        • c. 如何識別孤兒進程?
  • 三、進程優先級與調度策略
    • 3.1 基本概念
    • 3.2 優先級體系:PRI 與 NI 的協同
    • 3.3 調度的核心矛盾:競爭、獨立、并行與并發
  • 四、進程切換:內核級上下文管理
    • 4.1 進程切換的核心步驟
    • 4.2 切換背后的 “原子操作”
    • 4.3 進程切換的開銷
  • 五、Linux 2.6 內核調度隊列:O (1) 算法的經典實現
    • 5.1 調度隊列架構:雙向鏈表與位圖的精妙組合
    • 5.2 active指針和expired指針

引言

在操作系統的龐大體系中,進程是當之無愧的核心樞紐 —— 它是程序從代碼到動態執行的 “生命載體”,是內核調度資源的最小單元,更是理解操作系統如何協調硬件與軟件的關鍵切入點。從進程控制塊(PCB)對進程狀態的精細描述,到調度隊列對 CPU 資源的高效分配,每一個機制都蘊含著計算機科學的精妙設計。

本文將深入進程的 “內核視角”,解析task_struct如何通過雙向鏈表編織成復雜的進程網絡,探討僵尸進程與孤兒進程的資源管理哲學,揭示優先級調度與進程切換的底層邏輯。無論你是想夯實操作系統基礎的學習者,還是渴望深入內核機制的開發者,都能從中窺見計算機系統如何通過進程管理實現 “有序的并發奇跡”。

一、進程基礎:概念與核心數據結構

1.1 進程的本質:程序的動態化身

  • 《操作系統概念》中指出:進程是程序的執行實例
  • 內核視角:資源分配的最小單元

1.2 進程控制塊(PCB):內核管理的靈魂

  • 進程信息被放在一個叫做進程控制塊的數據結構中,可以理解為進程屬性的集合。
  • Linux下的PCB是task_struct
struct task_struct {// 1. 進程標識與狀態pid_t pid;                // 進程唯一 IDpid_t ppid;               // 父進程 IDvolatile long state;      // 狀態(如 TASK_RUNNING, TASK_INTERRUPTIBLE)struct task_struct *parent; // 父進程指針// 2. 內存與資源管理struct mm_struct *mm;     // 虛擬內存描述(頁表、地址空間)struct files_struct *files; // 文件描述符表(打開的文件)struct fs_struct *fs;     // 文件系統上下文(根目錄、當前目錄)// 3. CPU 上下文(執行狀態)struct thread_struct thread; // 寄存器、棧等線程信息(Linux 中進程與線程統一)unsigned long thread_saved_pc; // 程序計數器(PC)// 4. 調度與優先級int prio;                 // 動態優先級(影響 CPU 調度)struct sched_entity se;   // CFS 調度器實體(公平調度)// 5. 信號與 IPCsigset_t blocked;         // 阻塞的信號集合struct sigpending pending; // 待處理信號struct sem_undo *semundo; // 信號量 undo 操作(IPC 回滾)// 6. 其他元數據char comm[TASK_COMM_LEN]; // 進程名(如 "bash")struct list_head tasks;   // 進程鏈表(內核維護的進程列表)
};

在運行時,它會被加載到內存中。

組織進程
Linux是通過雙向循環鏈表的形式來組織 task_struct 的。它是通過在 task_struct 中嵌入了鏈表節點來實現雙向循環鏈表的。

1.2.1 鏈表節點嵌入

  1. list_head結構體
    內核定義通用雙向鏈表節點:
struct list_head {struct list_head *next, *prev; // 雙向指針
};
  1. task_struct中的鏈表成員
    每個進程的 task_struct 包含 list_head 類型的成員(如 tasks),作為鏈表節點:
struct task_struct {struct list_head tasks; // 連接到全局進程鏈表// 其他成員(如PID、狀態、內存管理等)
};

1.2.2 鏈表操作宏

通過一個宏來計算 task_struct 的起始地址。
接下來就有意思了,你都知道 task_struct 的起始地址了,然后通過對它的設計,我們是能夠保證它在一定的偏移量上是用于保存什么的結構。因而可以利用偏移量和強轉指針類型實現類型無關的鏈表操作

1.2.3 全局鏈表管理

  1. 進程鏈表頭
    內核以 init_task(0 號進程的 task_struct)為頭節點,維護全局進程鏈表。所有進程通過 tasks 成員鏈接到該鏈表,形成進程樹。
  2. 多鏈表共存
    task_struct 可通過不同的 list_head 成員屬于多個鏈表(如:
    • run_list:就緒隊列(CPU 調度時使用)。
    • wait_list:等待隊列(I/O 阻塞時使用)。
      ),實現進程在不同狀態(運行、就緒、阻塞)下的動態管理。

1.3 進程查看與系統調用

  1. 進程的信息可以通過 /proc 系統文件夾查看
    在這里插入圖片描述
    如:要獲取PID為1的進程信息,你需要查看 /proc/1 這個文件夾。

  2. 大多數進程信息也可以使用 top 、ps 這些用戶級工具來獲取

ps aux | grep test | grep -v grep

我們這里讓程序一直休眠,查看一下進程
在這里插入圖片描述
在這里插入圖片描述
使用另一個終端進行查看:
在這里插入圖片描述

1.3.1 通過系統調用獲取進程標識符

在這里插入圖片描述
在這里插入圖片描述

1.3.2 通過系統調用創建子進程

這里我們需要知道:

  • fork 雖然是一次調用,但是它有兩個返回值
  • 父子進程代碼共享,數據各自開辟空間,私有一份(采用寫實拷貝)
    在這里插入圖片描述
    在這里插入圖片描述
    可以看到,父進程 ret 接收到的返回值和子進程的 pid 是相同的!但是子進程的 ret 為 0。

為什么會有兩個返回值呢?

  1. 父進程返回值
    • 父進程調用 fork 進入內核態之后,內核復制出子進程并分配新 pid
    • 父進程從內核態返回時,直接返回子進程的 pid,因此父進程 fork 的返回值是子進程的PID
  2. 子進程返回值
    • 我們前面提到過,子進程在創建的時候,代碼和父進程共享,但是它會復制父進程的數據,但內核會做一件事:把子進程用來存儲返回值的寄存器,強制設置為0,所以子進程從內核態返回到用戶態時,fork 的返回值為 0,以便于識別子進程。

還有一個問題:
我們這里的 ret 不是一個變量嗎?為什么它能同時讓 else if(ret == 0)else 成立呢?
這個有了上面父子進程的返回值不同解釋起來也簡單。
本質是:fork 讓父子進程成為兩個獨立執行流,而前面說了,子進程的數據是拷貝自父進程的,但是內核對子進程 fork 的返回值進行了修改,所以看似 “一個變量滿足多個分支”,實際是 “兩個進程、兩個變量副本”,所以能讓父進程走 else、子進程走 else if ,產生 “同時成立” 的錯覺 。

二、進程生命周期:狀態與特殊場景

2.1 進程的幾個狀態

進程標準狀態

  1. R(Running)
    運行態:進程正在 CPU 上執行。
  2. S(Sleeping)
    睡眠態 / 阻塞態:進程因等待資源(如 I/O 完成)而暫停執行。
    細分可能包括:
    • D(Disk Sleep):不可中斷睡眠,通常因等待磁盤 I/O 而阻塞,無法被信號喚醒。
    • S(Interruptible Sleep):可中斷睡眠,能被信號喚醒。
  3. T(Stopped)
    暫停態 / 停止態:進程被暫停(如通過SIGSTOP信號),保留當前狀態,可恢復。
  4. Z(Zombie)
    僵尸態:進程已終止,但父進程尚未回收其退出狀態(PCB 殘留)。
  5. X(Dead)
    死亡態:進程已完全終止,資源被徹底釋放(此狀態通常不可見,因進程已消失)。

補充狀態(非標準但常見)

  1. I(Idle)
    空閑態:某些系統中用于表示內核線程或空閑進程。
  2. W(Waiting)
    等待態:與阻塞態類似,等待特定事件。
  3. K(Killed)
    被殺死:進程接收到終止信號(如SIGKILL),正在被清理。
  4. t (Tracing Stop)
    調試追蹤暫停態(因調試器 ptrace 追蹤觸發,如 gdb 調試時遇到斷點)。

2.2 進程狀態查看

ps aux # 側重資源監控(CPU / 內存占用)
ps axj # 側重進程關系(父子 / 組 / 會話結構)
  • a:顯示一個終端所有的進程,包括其他用戶的進程。
  • x:顯示沒有控制終端的進程,例如后臺運行的守護進程。
  • j:顯示進程歸屬的進程組ID、會話ID、父進程ID,以及與作業控制相關的信息
  • u:以用戶為中心的格式顯示進程信息,提供進程的詳細信息,如用戶、CPU和內存使用情況等

2.3 僵尸進程與孤兒進程:資源管理的兩面性

2.3.1 僵尸進程

a. 什么是僵尸進程?
  • 定義
    子進程已經正常終止運行,但父進程尚未調用 wait()waitpid() 系統調用來回收其進程控制塊(PCB,Process Control Block)和退出狀態時,子進程會暫時處于僵尸狀態(Zombie State),簡稱 僵尸進程
  • 狀態標識
    在 Linux 中,通過 ps 命令查看進程時,僵尸進程的 STAT 字段會顯示為 Z(Zombie 的首字母),例如:
PID   PPID  STAT  COMMAND
1234  5678  Z+    [defunct]
  • 僵尸進程會以終止狀態保持在進程表中,并且會一直在等待父進程讀取退出狀態碼。
  • 所以,只要子進程退出,父進程還在運行,但父進程沒有讀取子進程狀態,子進程進入 Z 狀態。
b. 僵尸進程的成因
  1. 父子進程的生命周期差異
    • 父進程創建子進程后,子進程先于父進程結束運行。
    • 子進程終止時,內核會保留其退出狀態少量資源(如 PID、運行時間等),直到父進程調用 wait() 獲取這些信息。
    • 若父進程未及時調用 wait(),子進程就會變成僵尸進程
  2. 常見場景
    • 父進程邏輯缺陷:父進程未編寫回收子進程的代碼(如未使用 wait())。
    • 父進程阻塞或死循環:父進程因等待其他資源而無法執行 wait()
c. 僵尸進程的危害
  1. 占用進程號(PID)資源
    • 系統中 PID 的數量有限(通常默認最大值為 32768 或更高),大量僵尸進程會耗盡 PID 資源,導致系統無法創建新進程。
  2. 影響進程監控
    僵尸進程雖不占用 CPU、內存等運行資源,但會干擾管理員對進程狀態的判斷(如通過 ps 命令看到無效進程)。
  3. 潛在的程序 bug 信號
    • 僵尸進程通常是程序中資源管理不當的表現,可能預示代碼存在邏輯漏洞(如未處理子進程退出)。
d. 如何識別僵尸進程?
  1. 使用 ps 命令過濾:
    • 輸出中 STATZ 的進程即為僵尸進程,PPID 是其父進程的 PID。
ps aux | grep Z
# 或
ps -e -o stat,ppid,pid,cmd | grep '^Z'
  1. 查看進程狀態文件:
    • 若顯示 State: Z (zombie),則為僵尸進程。
cat /proc/[PID]/status | grep State

2.3.2 孤兒進程

孤兒進程(Orphan Process) 是操作系統中與 僵尸進程 相對的概念,同樣涉及父子進程的生命周期管理。

a. 什么是孤兒進程?
  • 定義
    父進程先于子進程終止,且子進程尚未結束時,子進程會被 init 進程(PID=1) 接管,成為 孤兒進程
    • init 進程是系統啟動后的第一個進程,負責管理所有孤兒進程的生命周期。
  • 核心特點
    孤兒進程的 父進程 PID(PPID)會被重置為 1(即 init 進程的 PID),由 init 進程自動回收其資源,因此 不會產生資源泄漏問題
b. 孤兒進程與僵尸進程的對比
特性孤兒進程僵尸進程
成因父進程先于子進程終止子進程先終止,父進程未回收
父進程 PID被重置為 1(init 進程)保持原父進程 PID
資源管理init 進程自動回收資源父進程需手動回收,否則殘留
危害無(資源會被正常釋放)可能耗盡 PID 資源
狀態標識正常運行狀態(如 S、R)狀態為 Z(僵尸狀態)
c. 如何識別孤兒進程?
  1. 使用 ps 命令查看進程的父進程 PID(PPID):
    • 若某進程的 PPID 為 1,且狀態正常(非 Z),則為孤兒進程。
ps -ef | grep [子進程關鍵詞]
# 或
ps aux --forest | grep PID
UID        PID  PPID  C STIME TTY          TIME CMD
user     12345     1  0 10:00 ?        00:00:00 [orphan_process]
  1. 通過 /proc 文件系統查看:
cat /proc/[PID]/status | grep PPid
# 輸出示例:PPid: 1

三、進程優先級與調度策略

3.1 基本概念

  • 優先級本質
    進程優先級是一個 數值參數,用于標識進程獲取 CPU 時間的 相對重要性。優先級越高的進程,越容易被 CPU 調度執行。
  • 核心目標
    1. 系統穩定性:確保關鍵系統進程(如內存管理、設備驅動)優先運行。
    2. 響應性:提升交互式進程(如終端、GUI 應用)的響應速度,改善用戶體驗。
    3. 資源公平性:避免低優先級進程長時間饑餓(Starvation)。

查看系統進程

ps -l

在這里插入圖片描述
其中:

  • UID:代表執行者的身份
  • PID:代表這個進程的代號
  • PPID:代表這個進程是由哪個進程發展衍生而來的,亦即父進程的代號
  • PRI:代表這個進程可被執行的優先級,其值越小越早被執行
  • NI:代表這個進程的nice值

3.2 優先級體系:PRI 與 NI 的協同

  • RPI 很好理解,就和比賽排名一樣,數值越低,優先級越高
  • NI 也就是 nice 值,表示進程可被執行的優先級的修正數值,范圍為 [-20, 19],默認為 0
  • PRI(new)= PRI(old)+ nice

查看進程優先級

top

輸入 top 進入:
在這里插入圖片描述
在這個界面按 r -> 輸入進程PID -> 輸入nice值就能修改已存在進程的 nice 值了

3.3 調度的核心矛盾:競爭、獨立、并行與并發

在操作系統中,資源是有限的,但是又存在很多的進程,這就導致了存在以下幾種關系:

  1. 競爭
    指多個進程因爭奪 共享資源(如 CPU、內存、文件、I/O 設備等)而產生的相互制約關系。
  2. 獨立
    指進程在邏輯上 互不干擾,各自擁有獨立的運行環境和資源,執行結果僅取決于自身邏輯,與其他進程無關。
  3. 并行
    多個進程在同一時刻 同時執行,依賴 多核 CPU 或多處理器 硬件,每個任務分配到獨立的計算單元(如 CPU 核心)。
  4. 并發
    多個進程或線程在同一時間段內交替執行,通過 CPU 時間片輪轉(如分時系統)或事件驅動機制,在宏觀上呈現 “同時運行” 的效果,但微觀上同一時刻僅執行一個任務。

四、進程切換:內核級上下文管理

在操作系統中,進程切換(Process Switch) 是實現多任務并發執行的核心機制。當操作系統需要從一個進程切換到另一個進程時,會執行一系列復雜的操作,以確保上下文環境的正確保存和恢復。

4.1 進程切換的核心步驟

  1. 保存當前進程的上下文
    • 硬件上下文:
      • CPU 寄存器(如通用寄存器、程序計數器 PC、棧指針 SP)。
      • 處理器狀態(如標志位、特權級別)。
    • 軟件上下文:
      • 進程控制塊(PCB)中的信息,包括進程狀態、內存管理信息(頁表)、打開文件列表等。
  2. 更新進程狀態
    將當前進程的狀態從 運行態 改為 就緒態阻塞態,并將其 PCB 插入相應隊列(就緒隊列或阻塞隊列)。
  3. 選擇新進程
    調度器根據調度算法(如優先級調度、輪轉調度)從就緒隊列中選擇一個新進程。
  4. 恢復新進程的上下文
    • 從新進程的 PCB 中加載寄存器值、內存映射等信息。
    • 更新內存管理單元(MMU)的頁表,切換虛擬地址空間。
  5. 執行上下文切換
    通過 特權指令(如 x86 的iret)將控制權轉移到新進程的程序計數器(PC)指向的指令處,開始執行新進程。

4.2 切換背后的 “原子操作”

進程切換通常由以下事件觸發:

  1. 時間片耗盡
    進程在 CPU 上執行的時間超過分配的時間片(如 Linux 默認 10-20ms),調度器強制切換。
  2. 進程阻塞
    進程因等待資源(如 I/O、鎖、信號量)主動進入阻塞狀態,釋放 CPU。
  3. 高優先級進程就緒
    新的高優先級進程進入就緒隊列,搶占當前低優先級進程。
  4. 進程終止
    進程執行完畢或被強制終止,釋放 CPU 資源。
  5. 系統調用 / 中斷
    進程執行系統調用(如read())或發生硬件中斷(如時鐘中斷),CPU 從用戶態切換到內核態,由內核決定是否切換進程。

4.3 進程切換的開銷

進程切換會帶來一定的性能開銷,主要包括:

  1. 上下文保存 / 恢復開銷
    寄存器讀寫、PCB 操作等指令執行需要時間。
  2. 內存訪問開銷
    切換頁表會導致 TLB(Translation Lookaside Buffer)失效,后續內存訪問需重新查詢頁表,增加延遲。
  3. CPU 緩存失效
    新進程的指令和數據可能不在 CPU 緩存中,導致緩存缺失(Cache Miss),降低執行效率。

五、Linux 2.6 內核調度隊列:O (1) 算法的經典實現

5.1 調度隊列架構:雙向鏈表與位圖的精妙組合

在這里插入圖片描述
這張圖是 Linux 2.6 內核進程調度隊列(runqueue)的結構示意圖

下面來解釋一下這張圖:

一個單核 CPU 維護著一個 runqueue

  1. 運行隊列(runqueue)組成

    • 元數據:包含鎖(lock)、運行進程數(nr_running)、CPU 負載因子(cpu_load)等,用于調度控制和狀態統計。
    • 雙隊列設計
      • 活躍隊列(array[0],藍色框):存儲時間片未耗盡的進程,通過 nr_active(活躍進程數)、bitmap[5](位掩碼,快速標記非空優先級隊列)、queue[140](140 個優先級鏈表,同優先級進程按 FIFO 排列)管理。
      • 過期隊列(array[1],紅色框):存儲時間片耗盡的進程,結構與活躍隊列相同,通過activeexpired指針輪換(活躍隊列為空時交換,重新分配時間片,避免進程饑餓)。
  2. 優先級與隊列管理

    • 優先級范圍0~1390~99 實時優先級,100~139 普通優先級,對應nice值 -20~19)。
    • queue[140]:每個優先級對應一個雙向鏈表,進程按優先級分組,同優先級 FIFO 調度。
    • bitmap[5]:5 個 32 位掩碼(共 160 位),快速定位最高優先級非空隊列(位運算實現 O (1) 查找,提升調度效率)。
  3. 任務結構(task_struct)

    • 進程通過run_list節點嵌入queue的雙向鏈表中,支持快速插入 / 刪除(如進程狀態切換、時間片耗盡時的隊列遷移)。
  4. O (1) 調度算法核心

    • 優先級范圍:0~139(共 140 個優先級,對應queue[140]數組,每個下標代表一個優先級)。
    • 位圖結構bitmap[5]由 5 個unsigned long(共 160 位)組成,每一位對應一個優先級隊列的空滿狀態。例如:
      • 優先級p對應bitmap[p/32]的第p%32位(如優先級 5 → bitmap[0]第 5 位,優先級 33 → bitmap[1]第 1 位)。

簡單總結
queue[140]是指一共有這么多優先級隊列。然后有進程進入運行隊列,就把對應的bitmap置為非0。在進程調度時,通過位運算找出第一個為1的比特位,再從對應優先級的優先級隊列中選擇進程進行調度,直到這個優先級隊列為空,且前面優先級均為空,才在下一個非空優先級隊列中選擇進程進行調度。

5.2 active指針和expired指針

上面對于這兩個指針只是簡單的提到了一句,這里還需要做些補充

  • active指針永遠指向活動隊列
  • expired指針永遠指向過期隊列

活動隊列的調度邏輯

  • 調度流程

    • 調度器通過active->bitmap快速定位最高優先級非空隊列(如idx=5),取出隊首進程執行。
    • 進程時間片耗盡后,從active->queue[idx]移除,加入expired->queue[idx],并標記expired->bitmap[idx]為非空。
  • 關鍵特性

    • 只出不進:active隊列在調度期間不接收新進程,確保原有進程按優先級有序執行。
    • 動態減少:隨著調度進行,active->nr_active遞減,expired->nr_active遞增。

過期隊列的輔助作用

  • 進程管理
    • 新進程直接加入expired隊列。
    • 時間片耗盡的進程從active隊列移入expired隊列。
    • 只進不出expired隊列在active隊列未空時不參與調度,僅積累進程。
  • 時間片重置
    • expired隊列切換為active隊列時,所有進程重新分配時間片(基于優先級計算),確保公平性

指針交換的觸發條件

  • 主動觸發
    • active->nr_active減至 0 時,內核自動執行swap(&active, &expired),交換指針指向。
    • 交換后,原expired隊列成為新的active隊列,原active隊列變為expired隊列。
  • 被動觸發
    • active隊列未空但存在更高優先級進程插入expired隊列,調度器會優先處理active隊列,直到其為空后再交換指針。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85697.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

信息學奧賽一本通 1570:【例 2】能量項鏈 | 1843:【06NOIP提高組】能量項鏈 | 洛谷 P1063 [NOIP 2006 提高組] 能量項鏈

【題目鏈接】 ybt 1570:【例 2】能量項鏈 ybt 1843:【06NOIP提高組】能量項鏈 洛谷 P1063 [NOIP 2006 提高組] 能量項鏈 【題目考點】 1. 動態規劃:區間動規 2. 環形序列 解決方法:破環為鏈 模板題:洛谷 P1880 [N…

旅游微信小程序制作指南

想創建旅游微信小程序嗎?知道旅游業企業怎么打造自己的小程序嗎?這里有零基礎小白也能學會的教程,教你快速制作旅游類微信小程序! 旅游行業能不能開發微信小程序呢?答案是肯定的。微信小程序對旅游企業來說可是個寶&am…

Vue3+Vite中lodash-es安裝與使用指南

在 Vue 3 Vite 項目中安裝和使用 lodash-es 的詳細指南如下: 一、為什么選擇 lodash-es? ES 模塊支持:lodash-es 以原生 ES 模塊格式發布,支持現代構建工具的 Tree Shaking 按需加載:只引入需要的函數,顯…

法律模型選型

當然可以,以下是關于法律法規相關模型的技術選型調研建議,適合算法實習生從0入手,并能交付有深度的調研報告: 一、調研背景與目標 目標:調研用于處理法律法規類任務的大模型與技術方案,明確適合本團隊的模…

軟件工程專業的本科生應該具備哪些技能

軟件工程專業的本科生需要具備扎實的技術基礎、良好的開發流程認知和一定的軟技能,以適應軟件開發行業的需求。以下從技術技能、開發流程與工具、軟技能、實踐能力等維度整理核心技能清單,供參考: 一、核心技術技能 1. 編程語言 - 必學基礎語…

[Java 基礎]類,面向對象的藍圖

首先需要區分類和對象都是啥? 類:類是一個模板,它描述一類對象的行為和狀態,類這個概念更像是下定義,更像是模板(橡皮泥膜具)。 對象:對象(不是女朋友)是類…

selenium-自動更新谷歌瀏覽器驅動

1、簡介 selenium最初是一個自動化測試工具,而爬蟲中使用它主要是為了解決requests無法直接執行JavaScript代碼的問題,因為有些網頁數據是通過JavaScript動態加載的。selenium本質是通過驅動瀏覽器,完全模擬瀏覽器的操作,比如輸入…

java從azure中讀取用戶信息

以下是用 Java 從 Azure AD 獲取用戶信息的完整實現方案&#xff0c;使用 Spring Boot 框架和 Microsoft 身份驗證庫 (MSAL)&#xff1a; 1. 添加 Maven 依賴 <dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.…

C# 數據庫訪問與ORM框架全面指南:從ADO.NET到Entity Framework Core

在現代應用開發中&#xff0c;數據持久化是核心需求之一。作為.NET生態系統中的主力語言&#xff0c;C#提供了豐富多樣的數據庫訪問技術和工具。本文將全面探討C#中的數據庫訪問方式&#xff0c;重點介紹三種主流ORM&#xff08;對象關系映射&#xff09;框架&#xff1a;Entit…

day19 leetcode-hot100-37(二叉樹2)

104. 二叉樹的最大深度 - 力扣&#xff08;LeetCode&#xff09; 1.深度優先遍歷&#xff08;遞歸&#xff09;ps:不好理解&#xff0c;所以我一般不喜歡用遞歸 思路 典型算法&#xff0c;用遞歸求出高度&#xff0c;每次都是深度優先。 具體算法 /*** Definition for a bi…

【LLMs篇】13:LLaDA—大型語言擴散模型

欄目內容論文標題大型語言擴散模型 (Large Language Diffusion Models)核心思想提出LLaDA&#xff0c;一種基于擴散模型的LLM&#xff0c;通過前向掩碼和反向預測過程建模語言分布&#xff0c;挑戰自回歸模型&#xff08;ARM&#xff09;在LLM領域的主導地位&#xff0c;并展示…

Deepfashion2 數據集使用筆記

目錄 數據類別: 篩選類別數據: 驗證篩選前2個類別: Deepfashion2 的解壓碼 數據類別: 類別含義: Class idx類別名稱英文名稱0短上衣short sleeve top1長上衣long sleeve top2短外套short sleeve outwear3長外套long sleeve outwear4裙子skirt5褲子trousers6連衣裙dre…

Java并發編程哲學系列匯總

文章目錄 并發編程基礎并發編程進階并發編程實踐 并發編程基礎 Java并發編程基礎小結 Java線程池知識點小結 詳解JUC包下各種鎖的使用 并發編程利器Java CAS原子類全解 深入理解Java中的final關鍵字 Java并發容器深入解析&#xff1a;HashMap與ArrayList線程安全問題及解…

git 之 stash

一、git stash&#xff1a;臨時保存工作區修改 作用 將當前工作目錄和暫存區的未提交修改保存到棧中&#xff0c;并恢復工作區到上一次提交的干凈狀態。 適用場景&#xff1a; 臨時切換分支修復緊急 Bug拉取遠程代碼前清理工作區保存實驗性代碼避免生成無效提交 常用命令&am…

vxe-grid 雙擊行,打開expand的內容

1、官網api Vxe Table v4.6&#xff08;根據版本&#xff09; 要調用這個事件&#xff0c;雙擊單元格&#xff0c;我們打開type"expand"的內容 2、打開的事件toggleRowExpand 3、事件的說明 這個方法&#xff0c;會自動判斷當前展開的狀態&#xff0c;然后去觸發相…

Java Stream 高級實戰:并行流、自定義收集器與性能優化

一、并行流深度實戰&#xff1a;大規模數據處理的性能突破 1.1 并行流的核心應用場景 在電商用戶行為分析場景中&#xff0c;需要對百萬級用戶日志數據進行實時統計。例如&#xff0c;計算某時段內活躍用戶數&#xff08;訪問次數≥3次的用戶&#xff09;&#xff0c;傳統循環…

計算機系統結構-第5章-監聽式協議

監聽式協議******&#xff1a; 思想: 每個Cache除了包含物理存儲器中塊的數據拷貝之外&#xff0c;也保存著各個塊的共享狀態信息。 Cache通常連在共享存儲器的總線上&#xff0c;當某個Cache需要訪問存儲器時&#xff0c;它會把請求放到總線上廣播出去&#xff0c;其他各個C…

(c++)string的模擬實現

目錄 1.構造函數 2.析構函數 3.擴容 1.reserve(擴容不初始化) 2.resize(擴容加初始化) 4.push_back 5.append 6. 運算符重載 1.一個字符 2.一個字符串 7 []運算符重載 8.find 1.找一個字符 2.找一個字符串 9.insert 1.插入一個字符 2.插入一個字符串 9.erase 10…

學習筆記(24): 機器學習之數據預處理Pandas和轉換成張量格式[2]

學習筆記(24): 機器學習之數據預處理Pandas和轉換成張量格式[2] 學習機器學習&#xff0c;需要學習如何預處理原始數據&#xff0c;這里用到pandas&#xff0c;將原始數據轉換為張量格式的數據。 學習筆記(23): 機器學習之數據預處理Pandas和轉換成張量格式[1]-CSDN博客 下面…

LeetCode 2297. 跳躍游戲 VIII(中等)

題目描述 給定一個長度為 n 的下標從 0 開始的整數數組 nums。初始位置為下標 0。當 i < j 時&#xff0c;你可以從下標 i 跳轉到下標 j: 對于在 i < k < j 范圍內的所有下標 k 有 nums[i] < nums[j] 和 nums[k] < nums[i] , 或者對于在 i < k < j 范圍…