【Linux系統】進程概念

1. 進程概念

1.1 進程的本質

核心定義

  • 用戶視角:程序的動態執行實例(如同時運行多個Chrome窗口即多個進程)。

  • 內核視角:資源分配的最小實體單位,獨享CPU時間片、內存空間和文件資源。

  • 現代定義
    進程 = 內核數據結構(task_struct) + 程序代碼和數據段

進程不僅是“程序的執行實例”或“正在執行的程序”,從內核角度看,它是分配系統資源(CPU時間、內存)的實體。更精確地說,進程 = 內核數據結構(task_struct) + 程序代碼和數據。當程序被加載到內存時,操作系統為其創建一個task_struct實例,該結構體封裝了進程的所有屬性和狀態信息。生動示例:想象一個C程序(如hello.c)被編譯執行時,操作系統會動態分配內存和CPU時間片,并將程序指令映射到虛擬地址空間,同時初始化task_struct來跟蹤其狀態,就像給每個運行的程序貼上一個“身份證”和“健康記錄卡”。

示例:啟動兩個vim編輯不同文件時,系統創建兩個獨立進程,各自擁有獨立的代碼執行流和內存空間,互不干擾。

?我們先創建一個myprocess.c文件,然后死循環,每隔一秒打印

這里直接運行這個可執行程序,當我們把這個程序運行起來,其實就是一個進程


1.2?進程控制塊 (PCB)

task_struct:Linux的PCB實現

  • 存儲位置:常駐內存(RAM),由內核動態管理。

  • 關鍵字段分類(擴展版):

    字段類別具體內容
    標識符PID(進程ID)、PPID(父進程ID)、PGID(進程組ID)
    狀態運行態(TASK_RUNNING)、睡眠態(TASK_INTERRUPTIBLE)、僵尸態(EXIT_ZOMBIE)等
    內存指針代碼段(mm_struct->code_start)、數據段(mm_struct->data_start)指針
    上下文數據保存暫停時的CPU寄存器值(eip, eax等),用于恢復執行
    文件描述符表記錄打開的文件(files_struct結構體)
    資源限制最大文件打開數、CPU時間配額(struct rlimit

進程組織方式

// 內核源碼示例(簡化版)
struct task_struct {volatile long state;          // 進程狀態struct mm_struct *mm;         // 內存管理結構體pid_t pid;                    // 進程IDstruct files_struct *files;   // 打開文件表struct list_head tasks;       // 雙向鏈表指針// ... 其他字段
};
  • 全局進程鏈表:內核通過struct list_head tasks所有進程組成雙向鏈表,頭節點為init_task(PID=1的init進程)。


1.3?查看進程的實戰方法

1. /proc文件系統

  • 動態虛擬文件系統:以目錄形式暴露內核進程信息。

    # 查看PID為1的進程信息
    $ ls /proc/1
    exe -> /usr/lib/systemd/systemd  # 可執行文件鏈接
    cwd                              # 當前工作目錄
    fd/                              # 打開的文件描述符
    status                           # 進程狀態摘要

2. 命令行工具

# 顯示進程樹(含父子關系)
$ pstree -p
systemd(1)─┬─sshd(1234)───bash(5678)───vim(9012)└─crond(2345)# 動態監控進程
$ top -p 9012  # 監控PID 9012(vim進程)的資源占用

3. ps指令

一、ps?命令核心功能

作用:捕捉系統當前進程快照(非實時),用于:

  • 查看進程狀態(運行/睡眠/僵尸)

  • 分析資源占用(CPU/內存)

  • 定位問題進程

  • 查看進程間關系


二、參數詳解與使用場景
1. 基礎查看
命令作用示例輸出片段
ps aux查看所有用戶的所有進程USER PID %CPU %MEM VSZ RSS TTY...
ps ajx顯示進程樹關系(含PPID/PGID)PPID PID PGID SID TTY COMMAND...

輸出字段解析

  • VSZ:虛擬內存大小 (KB)

  • RSS:實際物理內存 (KB)

  • TTY:關聯終端(??表示無終端)

  • STAT:進程狀態(后文詳解)


2. 進程狀態(STAT)解碼
狀態碼含義說明
R運行中 (Running)正在執行或就緒狀態
S可中斷睡眠 (Sleeping)等待事件完成(如 I/O 操作)
D不可中斷睡眠 (Disk sleep)通常發生在磁盤 I/O,不可被信號中斷
T暫停狀態 (Stopped)被信號暫停(如?SIGSTOP
Z僵尸進程 (Zombie)進程已終止,但父進程未回收
<高優先級進程優先級高于默認值
N低優先級進程優先級低于默認值
s會話領導者 (Session leader)控制終端的進程
+前臺進程組 (Foreground group)與終端交互的進程

示例Ss+?= 會話領導者 + 可中斷睡眠 + 前臺進程


3. 高級過濾與顯示
參數組合作用示例應用場景
ps -e | grep ssh查找特定進程檢查 SSH 服務是否運行
ps -fC nginx顯示進程完整命令行 (-f) + 按名稱過濾查看 Nginx 配置參數
ps -p 1234 -o pid,ppid,cmd自定義輸出字段查看指定進程的父子關系
ps --forest樹形顯示進程層級分析進程派生關系
ps -eo pid,ppid,cmd --sort=-%mem按內存排序找出內存消耗最大的進程

1.4 獲取進程標識符(代碼解析)

我們可以通過man手冊來查看一下getpid

基本定義

  • 進程ID(PID)

    • 定義:進程ID(Process ID)是操作系統分配給每個進程的唯一標識符。它用于區分系統中的不同進程。
    • 作用
      • 資源分配:PID是分配系統資源(如內存、CPU時間等)的重要依據。

      • 進程控制:操作系統可以使用PID來對進程進行操作,例如啟動、停止、暫停或終止進程。

      • 唯一標識:每個進程在系統中都有一個唯一的PID,操作系統通過PID來管理進程。

    • 示例cat進程的PID為3538。

  • 父進程ID(PPID)

    • 定義:父進程ID(Parent Process ID)是指創建當前進程的進程的ID。每個進程都有一個父進程(除了初始進程)。

    • 作用

      • 進程關系:PPID用于表示進程之間的父子關系。通過PPID,可以追蹤進程的創建過程。

      • 資源繼承:子進程通常會繼承父進程的資源(如文件描述符、環境變量等)。

      • 進程管理:操作系統可以通過PPID來管理進程樹結構,例如在父進程終止時,清理其子進程。

    • 示例bash進程(PPID=2686)創建了cat進程(PID=3538),因此cat的PPID為2686。


核心特性

(1) 父子進程關系
  • 創建機制:父進程通過系統調用(如fork())創建子進程。子進程繼承父進程環境,但操作系統為其分配新PID,同時將其PPID設為父進程的PID。
    代碼示例(C++):

    pid_t t = fork();  // 創建子進程
    if (t == 0) {// 子進程:getpid()返回自身PID,getppid()返回父進程PIDcout << "子進程 PID:" << getpid() << " PPID:" << getppid() << endl; 
    } else {// 父進程:getpid()返回自身PIDcout << "父進程 PID:" << getpid() << endl; 
    }
    
  • 關系規則

    • 一個父進程可創建多個子進程,所有子進程共享同一PPID(即父進程PID)。
    • 子進程退出后,父進程需回收其資源,否則可能產生僵尸進程。(至于什么是僵尸進程后面章節會講)
(2) 特殊進程
  • init進程(PID=1)
    系統啟動的第一個進程(Linux中通常為systemd),是所有用戶進程的最終祖先,其PPID為0或-1(表示無父進程)。

    示例:進程表中PID=1的進程PPID為-1。
  • 內核進程(PID=0)
    管理內存交換等核心任務,無PPID。

注意:

數據類型本質
pid_t?是一個帶符號整數類型signed int),在 Linux 系統中被明確定義為?int?的別名。

  • 設計目的
    提供進程 ID 的抽象表示,屏蔽不同操作系統(如 Linux/Windows)或硬件架構(32/64 位)的底層差異,增強代碼可移植性。例如:

    • Linux 使用?pid_t?表示 PID,而 Windows 使用?HANDLE
    • 直接使用?int?可能導致平臺兼容性問題。

進程id示例:

我們修改一下之前的代碼

運行結果:

ltx@hcss-ecs-d90d:~/lesson2$ make
gcc -o myprocess myprocess.c
ltx@hcss-ecs-d90d:~/lesson2$ ./myprocess
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288
我是一個進程!我的pid:453288...

運行后我們可以發現可執行程序myprocess的pid是453288,我們還可以來驗證一下

使用ps指令來查看:

ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep
  • ps ajx

    • ps?是進程查看命令,用于顯示當前系統中的進程快照(非動態更新)。
    • 選項?ajx?指定輸出格式:a?顯示所有用戶進程,j?以作業控制格式顯示,x?包括無終端的進程(如后臺進程)。
    • 示例輸出:包含 PID(進程ID)、PPID(父進程ID)、COMMAND(命令名稱)等列。
  • | head -1

    • |?是管道符,將前一個命令的輸出作為后一個命令的輸入。
    • head -1?只保留輸出的第一行,即進程信息的表頭(如?PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND)。
    • 作用:確保后續進程信息有清晰的列名,便于閱讀。
  • &&

    • 邏輯與運算符,表示只有前一個命令(ps ajx | head -1)成功執行(返回狀態碼 0)時,才執行后續命令。
    • 這里用于分隔兩個獨立操作:先顯示表頭,再顯示進程詳情。
  • ps ajx | grep myprocess

    • 再次運行?ps ajx?獲取所有進程信息。
    • grep myprocess?過濾出包含關鍵字 "myprocess" 的行(通常是目標進程的命令名稱)。
    • 問題grep?命令自身在運行時也會被列為進程,且其命令中包含 "myprocess",因此會被錯誤地包含在結果中(例如輸出?grep --color=auto myprocess)。
  • | grep -v grep

    • grep -v?表示反向過濾,排除包含指定關鍵字 "grep" 的行。
    • 作用:移除?grep myprocess?自身產生的進程條目,避免干擾。例如,如果未加此部分,輸出會多出一行?grep --color=auto myprocess

如果我們想殺掉這個進程可以使用快捷鍵CTRL + c(左邊的Shell),或者在右邊的Shell中使用

kill -9 [想要殺掉的pid]

至于kill這個指令的是如何殺掉這個進程的,我們在后面的信號章節也會講到

父進程id示例:

再次修改一下代碼

運行

ltx@hcss-ecs-d90d:~/lesson2$ make
gcc -o myprocess myprocess.c
ltx@hcss-ecs-d90d:~/lesson2$ ./myprocess
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
我是一個進程!我的pid:451964,我的父進程id:450425
...

運行結果可看到進程pid為451964,父進程ppid為450425

同樣也可以在驗證一下

這里我們可以看到怎么這次的父進程ppid和上次的父進程ppid一樣,都是450425.

我們可以多次運行看一下

父進程id一直不變,這是什么情況呢?

我們也可以用ps來查一下

我們可以看到原來我們的父進程是bash

因為 你每次都是在同一個交互式 Bash 會話里手動啟動程序,所以:

  • Bash 是 Linux 默認的命令行解釋器(Shell),用戶通過終端輸入命令時,Bash 會創建子進程來執行這些命令

  • 父進程就是當前這個 Bash 進程

  • Bash 進程的 PID 在你退出或關閉終端之前不會改變

  • 于是你看到的 PPID 始終就是 那個 Bash 的 PID-bashbash)。

換句話說,只要你不關掉這個終端(或顯式 exit 掉這個 Bash),它就是所有你手動啟動命令的父進程,PPID 自然看起來“不變”。


1.5?fork() 機制深度解析

同樣我們可以使用man手冊來查一下

關鍵特性

  1. 一次調用,兩次返回

    • 父進程返回子進程PID(>0)

    • 子進程返回0

    • 失敗返回-1(如進程數超限)

  2. 寫時拷貝(Copy-On-Write)

    • 初始狀態:父子進程共享同一物理內存。

    • 修改觸發:當任一進程嘗試寫入數據時,內核為該進程復制新內存頁。

我們先來修改一下代碼,淺嘗一下fork

運行結果:

fork之后的代碼被執行了兩次,why?

fork: 如何呢?又能怎?

核心原理:一次調用,兩次返回

當程序執行到?fork()?系統調用時,操作系統會創建一個與原進程(父進程)幾乎完全相同的副本(子進程)。這個副本包括:

  1. 代碼段的復制(共享只讀)

  2. 數據段和堆棧的復制(寫時拷貝)

  3. 程序計數器(PC)位置 -?指向?fork()?之后的下一條指令

#include <stdio.h>
#include <unistd.h>int main() {printf("父進程開始運行,pid:%d\n", getpid());  // 步驟1:父進程執行fork();  // 步驟2:分水嶺!// ↓ 步驟3:此處開始有兩個獨立的執行流printf("進程開始運行,pid:%d\n", getpid());  // 步驟4:父子進程各執行一次return 0;
}

執行流程:

關鍵機制解析:

  1. 寫時拷貝 (Copy-On-Write)

    • 子進程創建時不立即復制物理內存

    • 父子共享相同物理內存頁(標記為只讀)

    • 當任一進程嘗試寫入內存時,觸發缺頁異常

    • 內核再為該進程復制新的內存頁

  2. 程序計數器繼承

    • 子進程創建時復制父進程的CPU寄存器狀態

    • 包括指向?fork()?后下一條指令的EIP寄存器

    • 因此子進程從?fork()?返回處開始執行

  3. 返回值差異

    返回值含義執行進程
    >0子進程PID父進程
    0成功創建標志子進程
    -1創建失敗父進程

要是我們想讓父子進程執行不同的代碼邏輯,應該怎么做呢

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{printf("父進程開始運行,pid:%d\n", getpid());pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id == 0){// childwhile(1){printf("我是一個子進程!我的pid:%d,我的父進程id:%d\n", getpid(), getppid());sleep(1);             }}else{// fatherwhile(1){printf("我是一個父進程!我的pid:%d,我的父進程id:%d\n", getpid(), getppid());sleep(1);             }}//printf("進程開始運行,pid:%d\n", getpid());//while(1)//{//    printf("我是一個進程!我的pid:%d\n", getpid());//    printf("我是一個進程!我的pid:%d,我的父進程id:%d\n", getpid(), getppid());//    sleep(1);//}return 0;
}

修改完代碼我們來運行一下

ltx@hcss-ecs-d90d:~/lesson2$ make
gcc -o myprocess myprocess.c
ltx@hcss-ecs-d90d:~/lesson2$ ./myprocess
父進程開始運行,pid:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425
我是一個子進程!我的pid:457988,我的父進程id:457987
我是一個父進程!我的pid:457987,我的父進程id:450425...

運行可以看到父進程myprocess可執行程序id為457987,父進程的父進程bash的id為450425,父進程的子進程id為457988。

1.?為什么fork要給父子進程返回不同的值?

這是為了在代碼中區分父子進程的執行路徑,讓程序員能編寫不同的邏輯分支:

設計考量

  • 父進程需要知道子進程ID:用于后續管理(等待、發送信號等)

  • 子進程需要明確自身身份:避免遞歸創建進程

  • 錯誤處理統一:只有父進程能處理fork失敗

類比:就像雙胞胎出生時獲得不同的名字,雖然基因相同但身份不同

2.?為什么fork會"返回兩次"?

實際上不是函數返回兩次,而是創建了兩個獨立的執行流

關鍵機制

  1. 調用fork時,內核復制父進程的:

    • 寄存器狀態(包括程序計數器PC)

    • 頁表(通過寫時拷貝)

    • 文件描述符表

  2. 返回用戶空間前,內核修改:

    • 父進程的EAX寄存器 = 子進程PID

    • 子進程的EAX寄存器 = 0

  3. 兩個進程從相同的代碼位置繼續執行:

    • 父進程:從fork()調用后繼續

    • 子進程:"誕生"后的第一條指令就是fork()之后的代碼

3.?為什么同一個變量既等于0又大于0?

核心原理:兩個進程擁有獨立的地址空間

int ret = fork();  // 這行代碼在兩個進程中都有!// 內存布局示意:
// 父進程內存空間:ret_addr = 0x1000, 值=457988(子進程PID)
// 子進程內存空間:ret_addr = 0x1000, 值=0

執行過程

時間線        父進程(PID=457987)                子進程(PID=457988)
---------------------------------------------------------------T1         執行 fork() 系統調用T2             |                            內核創建子進程T3             |                            設置父進程返回值=457988T4             |                            設置子進程返回值=0T5         從fork返回 ↓T6         ret = 457988 (>0)                從"誕生點"開始執行 ↓T7         執行 else 分支                    ret = 0 (==0)T8         printf("Parent...")              執行 else if 分支T9                                          printf("Child...")

注意:ret?不是同一個物理內存位置!父子進程有各自獨立的變量副本。

技術本質:寫時拷貝(COW)的作用

int global = 100;  // 全局變量pid_t pid = fork();if (pid == 0) {global = 200;  // 子進程修改
} else {sleep(1);printf("%d", global); // 父進程仍輸出100
}

內存變化

  1. fork時:父子共享同一物理內存頁(標記為只讀)

  2. 子進程寫global:觸發頁錯誤

  3. 內核復制該內存頁給子進程

  4. 子進程在新頁上修改值

  5. 父進程仍訪問原內存頁

總結要點

  1. 進程是資源容器:通過task_struct實現資源隔離與調度。

  2. fork()是進程分身術:通過寫時拷貝高效復制,雙返回值區分父子。

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

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

相關文章

從LLM到VLM:視覺語言模型的核心技術與Python實現

本教程的完整代碼可以在GitHub上找到&#xff0c;如果你有任何問題或建議&#xff0c;歡迎交流討論。 引言&#xff1a;為什么需要VLM&#xff1f; 當我們與ChatGPT對話時&#xff0c;它能夠理解復雜的文字描述&#xff0c;生成流暢的回答。但如果我們給它一張圖片&#xff0c…

老系統改造增加初始化,自動化數據源配置(tomcat+jsp+springmvc)

老系統改造增加初始化&#xff0c;自動化數據源配置一、前言二、改造描述1、環境說明2、實現步驟簡要思考三、開始改造1、準備sql初始化文件2、啟動時自動讀取jdbc文件&#xff0c;創建數據源&#xff0c;如未配置&#xff0c;需要一個默認的臨時數據源2.1去掉sping mvc原本配置…

衛星通信終端天線的5種對星模式之二:DVB跟蹤

要實現穩定可靠的衛星通信&#xff0c;地面終端天線必須精準地對準遠方的衛星。對星的過程是一個不斷搜索、不斷逼近的過程&#xff0c;其目標是讓天線波束中心精確指向衛星&#xff0c;從而獲得最大信號接收與發射效率。 衛星通信終端天線的對星技術是保障衛星通信鏈路穩定的…

重構下一代智能電池“神經中樞”:GCKontrol定義高性能BMS系統級設計標桿

概述BMS&#xff08;電池管理系統&#xff09;作為新能源汽車動力電池與整車的核心紐帶&#xff0c;通過實時監控電壓、電流、溫度及SOC等參數&#xff0c;控制電池充放電過程&#xff0c;保障電池安全性與使用壽命。隨著電動汽車智能化發展&#xff0c;對BMS的響應速度、精度和…

面試150 對稱二叉樹

思路 聯想遞歸三部曲&#xff1a;傳入參數、遍歷方式、返回什么。本題聯想到先序遍歷的方式,需要遍歷整顆二叉樹,最后返回的是一個布爾值。然后我們需要傳入的是左子樹和左子樹的節點,然后分別進行比較。 # Definition for a binary tree node. # class TreeNode: # def __…

多線程的區別和聯系

進程和線程的區別和聯系1.一個進程可以包含多個線程&#xff0c;不能夠沒有線程2.進程是系統資源分配的基本單位&#xff0c;線程是系統調度執行的基本單位3.同一個進程里的線程之間&#xff0c;共用同一份系統資源4.線程是當下實現并發編程的主流方式&#xff0c;通過多線程&a…

兩個文件夾自動同步

兩個文件夾自動同步&#xff0c;非常簡單&#xff0c;利用一些工具就可以輕松做到&#xff0c;設置完源和目標文件夾&#xff0c;點擊啟動就馬上可以兩個文件夾自動同步&#xff0c;對于一些有文件同步、文件災備需求的老登&#xff0c;用起來會非常順手&#xff0c;比如PanguF…

虛擬商品交易維權指南:數字經濟時代的消費者權益保護

首席數據官高鵬律師數字經濟團隊創作AI輔助在元宇宙、NFT、虛擬情緒產品等新興領域蓬勃發展的今天&#xff0c;虛擬商品交易已成為數字經濟的重要組成部分。從游戲皮膚、在線課程到數字藏品&#xff0c;消費者在享受虛擬商品便捷性的同時&#xff0c;也面臨著諸多法律風險。作為…

mysql 一條語句的執行流程

文章目錄一條查詢語句的執行流程連接器管理連接權限校驗分析器優化器采樣統計優化器選錯索引改正執行器查詢緩存存儲引擎一條update語句的執行流程redo logredo log buffer結構redo log日志類型寫入時機配置innodb_flush_log_at_trx_commitbinlogredo log和binlog 對比配置兩階…

【視頻觀看系統】- 需求分析

&#x1f3af; 一、項目目標 構建一個功能完備的視頻觀看網站&#xff0c;用戶可以上傳、瀏覽、觀看視頻&#xff0c;并在觀看過程中實時發送/接收彈幕。系統具備良好的性能、可擴展性與用戶體驗&#xff0c;未來可逐步擴展為多媒體平臺。&#x1f464; 二、用戶角色分析用戶類…

模型驅動的架構MDA的案例

在一個企業資源規劃&#xff08;ERP&#xff09;系統開發項目中&#xff0c;目標是為一家中型制造企業打造一套高效且可擴展的管理系統&#xff0c;涵蓋訂單處理、庫存管理等多個業務模塊。項目團隊采用了 MDA 的設計思想進行開發。?首先是業務需求分析與計算獨立模型&#xf…

第一次搭建數據庫

本文詳細介紹第一次搭建數據庫安裝和配置過程, 包括卸載舊版本、下載安裝、配置服務、環境變量等等 第一步下載mysql 在下載之前需要檢查電腦上有沒有安裝mysql, 如果有再安裝, 80%就會有問題 檢查方法: 電腦-右鍵找到管理-服務-在服務中找有沒有mysql服務若有請先 1.停止服務 …

洛谷題解 | UVA1485 Permutation Counting

目錄題目描述題目思路AC 代碼題目描述 https://onlinejudge.org/external/14/p1485.pdf 題目思路 dp。 定義 dpi,jdp_{i,j}dpi,j? 為前 iii 個數的排列中恰好有 jjj 個小于號的排列總數。 考慮將數字 iii 插入到前 i?1i-1i?1 個數的排列中不同的位置&#xff1a; 如果…

飛算科技:以原創技術賦能電商企業數字化轉型

在電商行業從流量競爭邁向精細化運營的當下&#xff0c;技術能力已成為決定企業生存與發展的核心要素。然而&#xff0c;高并發場景下的系統穩定性、個性化推薦算法的迭代效率、營銷活動的快速響應等挑戰&#xff0c;讓許多電商企業陷入“技術投入大、見效慢”的困境。作為國家…

人工智能自動化編程:傳統軟件開發vs AI驅動開發對比分析

人工智能自動化編程&#xff1a;傳統軟件開發vs AI驅動開發對比分析 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量…

用java實現一個自定義基于logback的日志工具類

? 動態創建: 無需配置文件&#xff0c;通過代碼動態創建logback日志對象 ? Class對象支持: 使用LogUtil.getLogger(MyClass.class)的方式獲取日志 ? 日期格式文件: 自動生成info.%d{yyyy-MM-dd}.log格式的日志文件 ? 文件數量管理: 只保留最近3個文件&#xff0c;自動刪除歷…

面試現場:奇哥扮豬吃老虎,RocketMQ高級原理吊打面試官

“你了解RocketMQ的高級原理和源碼嗎&#xff1f;” 面試官推了推眼鏡&#xff0c;嘴角帶笑&#xff0c;眼神里透著一絲輕蔑。 奇哥笑而不語&#xff0c;開始表演。面試場景描寫 公司位于高樓林立的CBD&#xff0c;電梯直達28樓。面試室寬敞明亮&#xff0c;空氣中混著咖啡香與…

Django Nginx+uWSGI 安裝配置指南

Django Nginx+uWSGI 安裝配置指南 引言 Django 是一個高級的 Python Web 框架,用于快速開發和部署 Web 應用程序。Nginx 是一個高性能的 HTTP 和反向代理服務器,而 uWSGI 是一個 WSGI 服務器,用于處理 Python Web 應用。本文將詳細介紹如何在您的服務器上安裝和配置 Djang…

外設數據到昇騰310推理卡 之二dma_alloc_attrs

目錄 內核源碼及路徑 CONFIG_DMA_DECLARE_COHERENT DTS示例配置 dma_direct_alloc 特殊屬性快速路徑 (DMA_ATTR_NO_KERNEL_MAPPING) 主體流程 1. 內存分配核心 2. 地址轉換 3. 緩存一致性處理 映射 attrs不同屬性的cache處理 cache的標示&#xff08;ARM64&#xff0…

Java 大視界:基于 Java 的大數據可視化在智慧城市能源消耗動態監測與優化決策中的應用(2025 實戰全景)

??摘要??在“雙碳”戰略深化落地的 2025 年&#xff0c;城市能源管理面臨 ??實時性??、??復雜性??、??可決策性?? 三重挑戰。本文提出基于 Java 技術棧的智慧能源管理平臺&#xff0c;融合 ??Flink 流處理引擎??、??Elasticsearch 實時檢索??、??ECh…