Linux深度探索:進程管理與系統架構

在這里插入圖片描述

1.馮諾依曼體系結構

我們常見的計算機,如筆記本。我們不常見的計算機,如服務器,大部分都遵守馮諾依曼體系。
在這里插入圖片描述
截至目前,我們所認識的計算機,都是由?個個的硬件組件組成。

  • 輸入設備:鍵盤,鼠標,話筒,攝像頭,…,網卡,磁盤
  • 輸出設備:顯示器,磁盤,網卡,打印機,…
  • 中央處理器(CPU):含有運算器和控制器等
    我們把輸入輸出設備稱為外設。
    磁盤(硬盤):外存

關于馮諾依曼,必須強調幾點

  • 這里的存儲器指的是內存;
  • 不考慮緩存情況,這里的CPU能且只能對內存進行讀寫,不能訪問外設(輸入或輸出設備);
  • 外設(輸入或輸出設備)要輸入或者輸出數據,也只能寫入內存或者從內存中讀取。
  • 一句話,所有設備都只能直接和內存打交道。

在學習C++進行文件操作時,讀文件操作本質是把磁盤中的數據讀取到內存中,寫文件則是將內存里的數據寫入對應的磁盤上,這類數據的讀寫動作被稱為Input/Output(IO)。
從硬件層面來說,站在內存的角度理解IO,當外部設備將數據傳輸給內存時,這一過程稱為Input(輸入),而當內存把數據傳輸給輸出設備時,這一過程就叫做Output(輸出)。


1.我們編譯好的軟件,它要運行必須先加載到內存?那程序運行之前在哪里?

  • 在磁盤,因為我們今天知道,程序就是個文件,它就是我們編譯好的,在我們磁盤特定路徑下的一個二進制文件。

2.為什么我們對應的程序,運行的時候必須得從我們對應的磁盤加載到我們內存呢?

  • 程序運行與內存加載:編譯好的軟件以二進制文件形式存于磁盤特定路徑下,要運行必須先加載到內存。因為在計算機體系結構里,軟件運行由CPU執行代碼、訪問數據,但CPU只能讀寫內存數據,無法直接讀取外設數據,所以程序需從磁盤(外設)加載到內存,該加載過程本質是Input,即把外設數據輸入到存儲器。
  • printf 執行原理:當程序在內存中運行并執行printf代碼時,數據不會直接打印到輸出設備,而是先存放在緩沖區,待需要時再刷新到外設。這同樣是馮·諾依曼體系結構的規定,printf在CPU中執行代碼,不能直接輸出到外設。
  • 數據流動與體系結構效率:數據流動本質是從一個設備“拷貝”到另一個設備。馮·諾依曼體系結構的效率由設備的“拷貝”效率決定。并且在數據層面,CPU只與內存打交道,外設也只與內存打交道。

3.馮諾依曼為什么是這種結構呢?計算機能否不使用內存,僅通過輸入設備、CPU和輸出設備運行?
在這里插入圖片描述

  • 存儲分級與特點:計算機中有多種存儲設備,如離CPU近的寄存器有存儲能力,內存離CPU較近,磁盤離CPU較遠。離CPU越遠存儲容量越大、效率越低但價格便宜,如4GB內存幾百塊,而同等價格可買約800T磁盤。
    在這里插入圖片描述
  • 效率差異問題:輸入輸出設備作為外設運算效率低(如磁盤為毫秒級),CPU運算速度快(納米級),兩者效率相差10?倍。若沒有內存,外設與CPU、輸出設備交互時,會因速度不匹配導致整個體系結構效率由外設決定(木桶原理)。

設想將所有存儲設備都換成寄存器可行,但會使計算機造價昂貴。

內存的作用及意義:為平衡效率和價格,計算機體系結構引入內存。內存可適配CPU和外設間的速度不匹配,使計算機既能以較低成本制造,又能有不錯的運行效率,當代計算機是性價比的產物。

4.為什么馮諾依曼體系結構從上個世紀五六十年代到現在,基本上是我們當代計算機的主流結構?

  • 主流結構原因:馮·諾依曼體系結構的歷史意義在于讓用戶能用較低價格買到效率不錯的計算機。隨著芯片技術、摩爾定律推動存儲技術發展,計算機變得更便宜且效率更高。如今以內存決定計算機效率,使普通人能買得起計算機,進而造就眾多網民和互聯網,該體系是構建互聯網的必要條件。

5.那為什么我們有了內存之后效率就高了呢?木桶定律里里面最短的依然是輸入輸出設備呀?

  • 內存提升效率原理:雖按木桶定律輸入輸出設備仍是短板,但后來出現的操作系統加載于內存中,它能用算法提前將外設數據搬到內存,配合局部性原理,讓CPU可直接讀取內存數據,從而使內存發揮最大效果提升效率。
    后續內容預告:后續將討論操作系統在該體系結構中扮演的角色和意義。

6.理解數據流動

舉個場景,你在北京,你的朋友在南京,今天你兩在QQ進行聊天,當你們兩個聊天的時候,請幫我解釋一下,今天你通過鍵盤輸入了一個“你好”,那么“你好”這個字符串信息是如何展現在你朋友的顯示器上的?如果是在qq上發送?件呢?
在這里插入圖片描述

  • QQ聊天數據流動:雙方用電腦QQ聊天,本質是兩臺馮·諾依曼體系設備交互。輸入方打開并登錄QQ,將QQ可執行程序加載到內存,通過鍵盤輸入信息,數據從鍵盤(輸入設備)流入內存(存儲器)。QQ對信息加密,經運算器運算、CPU處理后寫回內存,再通過網卡(輸出設備)發送到網絡。接收方網卡(輸入設備)獲取數據存入內存,啟動的QQ讀取數據交CPU解密,再寫回內存并刷新到顯示器(外設)顯示。
  • QQ發送文件數據流動:文件本質是數據,拖拽文件到QQ程序時,文件從磁盤拷貝到內存,QQ執行代碼加密、封包后寫回內存,再刷新到網卡發送。對方網卡接收文件數據存入內存,解包、解密后寫回內存,甚至打開目標文件,將數據寫入磁盤(輸出設備)。

總結:聊天是數據從用戶鍵盤經體系結構轉發到對方顯示器的過程;發送文件是文件從本地磁盤經體系結構拷貝至對方磁盤的過程,軟件的作用在于處理存儲器和內存之間的關系,數據流動本質是在馮·諾依曼體系中進行。

2.操作系統統(Operator System)

2-1概念

任何計算機系統都包含一個基本的程序集合,稱為操作系統(OS)。操作系統包括:

  • 內核(進程管理,內存管理,文件管理,驅動管理)
  • 其他程序(例如函數庫,shell程序等等)

在這里插入圖片描述
安卓系統基于Linux內核構建,負責管理手機硬件資源(CPU、內存、存儲等),其本質仍遵循馮·諾依曼架構。與傳統PC不同,手機通過觸摸屏實現輸入輸出的高度集成,交互界面需專門設計。為此,安卓在Linux內核之上新增了應用框架層(如圖形界面、API庫等),開發者可基于此開發移動應用。

對比Windows:

  1. 安卓采用分層架構,圖形界面運行于用戶空間,與內核解耦;
  2. Windows部分圖形驅動與內核深度耦合(如DirectX),但因系統閉源,具體細節未知。

2-2設計OS的目的:

  • 向下,與硬件交互,管理所有的軟硬件資源(不是目的,是手段)
  • 對上,為用戶程序(應用程序)提供一個良好的執行環境(用戶是目的)
    在這里插入圖片描述

1.軟硬件體系結構層狀結構;

2.訪問操作系統,必須使用系統調用——其實就是函數,只不過是系統提供的;

printf的本質:是你把你的數據寫到了硬件(顯示器)!

3.我們的程序,只要你判斷出它訪問了硬件,那么它就必須貫穿整個軟硬件體系結構;

4.庫可能在底層封裝了系統調用。

2-3核心功能

  • 在整個計算機軟硬件架構中,操作系統的定位是:?款純正的“搞管理”的軟件

2-4理解操作系統的“管理”

如何理解“管理”,我們下面舉個例子。
? 管理的例子——學生,輔導員,校長
? 要管理的對象:學生
? 進行管理的對象:校長
做這件事情,管理者校長有決策權,輔導員進行執行,去管理學生。

在這里,操作系統= 校長,底層硬件=學生,驅動程序=輔導員

1.要管理,管理者和被管理者,可以不需要見面

2.管理者和被管理者,怎么管理呢?根據“數據”進行管理!

3.不需要見面,如何得到數據?由中間層獲取!

在這里插入圖片描述
校長管理學生,可以轉化為對Excel表格的數據的管理!
要是學生越來越多了,那校長的負擔越來越大,而這項工作的本質其實是對數據進行增刪查改

“校長”了解一點編程語言,它只會c語言——因為它是一個操作系統,操作系統是用C語言寫的。

在這里插入圖片描述
在這里插入圖片描述
日常的校長管理學生的工作,轉化為對鏈表的增刪查改!(其他數據結構也可)

這個建模的過程稱為**先描述,再組織!**

對任何“管理”場景進行建模都適用!

  • 總結計算機管理硬件:
  1. 描述起來,用struct結構體
  2. 組織起來,用鏈表或其他高效的數據結構

(類:解決先描述的問題;STL:解決的是再組織的問題。)

2-5理解系統調用

  • 系統調用與庫函數的關系:庫函數和系統調用處于上下層關系。從開發層面看,操作系統對外呈現為一個整體,并暴露部分接口,即系統調用。系統調用功能基礎,對用戶要求較高。開發者可對部分系統調用進行適度封裝形成庫,方便上層用戶或開發者進行二次開發。

  • 操作系統的服務:操作系統需向上層提供服務。像printf打印是將字符串寫到顯示器硬件,scanf讀入是從鍵盤讀取硬件數據到軟件程序,這些操作都需要操作系統參與,操作系統提供的訪問硬件的能力就是服務。同時,操作系統不信任任何用戶或人。

  • 系統調用的本質:系統調用本質上是操作系統提供的函數調用。用戶要訪問操作系統獲取數據、設置信息等都需通過系統調用完成。由于Linux、Windows、macOS等操作系統基本由C語言編寫,所以提供的系統調用一般是C風格的C函數。函數有輸入參數(用戶提供給操作系統)和返回值(操作系統反饋給用戶),系統調用本質是用戶與操作系統之間的數據交互。

承上啟下: 我們啟動的軟件都會被加載到內存,因為馮諾依曼規定它必須得加載進來,在內存當中,當我們還沒有啟動軟件的時候,還有一款軟件在最開始就加載進來了,叫做操作系統(OS)。

OS必然要對多個被加載到內存中的程序進行管理,采取“先描述,再組織”的辦法。

3.進程

3-1基本概念與基本操作

在這里插入圖片描述

在這里插入圖片描述

  • 進程的組成:進程由內核數據結構對象和自身的代碼與數據構成。

3-2描述進程——PCB

基本概念
  • 進程信息被放在?個叫做進程控制塊的數據結構中,可以理解為進程屬性的集合。
  • 課本上稱之為PCB(process control block),Linux操作系統下的PCB是: task_struct
task_struct-PCB的?種
  • 在Linux中描述進程的結構體叫做task_struct。
  • task_struct是Linux內核的?種數據結構,它會被裝載到RAM(內存)?并且包含著進程的信息。

對進程理解的誤區:

  • 很多人錯誤地認為將程序和代碼加載到內存中就是進程。實際上,進程加載時,除了將代碼和數據加載到內存,操作系統還會在內部為其創建對應的task_struct結構體,該結構體可找到對應的代碼和數據。并且所有的task_struct在操作系統內常以鏈表形式被管理起來,因此操作系統對進程的管理最終轉化為對進程鏈表的增刪查改。

創建PCB的原因:

  • 操作系統為加載的進程創建對應的PCB(task_struct)結構體對象,是因為要管理進程。而管理進程必須先進行描述再組織,所以需要有描述進程的task_struct,之后通過特定數據結構(如鏈表)進行組織管理,這樣操作系統對進程的管理就轉變為對數據結構的增刪查改操作

3-3task_struct

內容分類:

在這里插入圖片描述

組織進程

可以在內核源代碼里找到它。所有運行在系統里的進程都以task_struct鏈表的形式存在內核里。

在這里插入圖片描述

3-4查看進程

我們歷史上執行的所有的指令、工具、自己的程序,運行起來,全部都是進程。

  1. 進程一旦啟動,我們可以使用ps來查所有進程axj,a表示所有。
    top也可以查所有進程。

如果我們只想看到我們自己剛啟動的進程,可以用下面的命令:
在這里插入圖片描述
在Linux中我們想同時執行兩條命令可以用分號相隔。分號可以用&&代替,效果相同。
在這里插入圖片描述
當我們去查進程的時候,對應的這個grep選項它總是會被顯示出來,為什么呢?

8993 11868 11867  8993 pts/1    11867 S+       0   0:00 grep --color=auto myprocess

因為整條命令從左向右查的時候,grep也是個命令,當它最終要把你對應的查顯示出來的結果做過濾的時候,grep命令一旦跑起來自己也是個進程,而它自己的過濾關鍵字里面本來就包括myprocess,所有它也會自己把自己查出來。

要是我們不想要查到grep可以使用下面命令:
在這里插入圖片描述
這樣就只會查到只是包含./myprocess對應進程ID8807了.

  1. 我們也可以通過一個Linux當中的目錄結構叫做proc目錄,也就是可以通過文件的形式去查看進程:
ls /proc

在操作系統中,不僅能用 ls 等命令通過目錄結構查看磁盤上的文件,還能以文件形式呈現內存相關數據,讓用戶動態查看。比如 /proc 是內存級文件系統,其數據都來自內存,與磁盤無關。由于 Linux 遵循“一切皆文件”的設計理念,在 Linux 的設計中,甚至每個進程都能轉化為若干個文件。

3-5通過系統調用獲取進程標示符
我們來學習第一個系統調用:getpid

在這里插入圖片描述

pid_t getpid(void);     //獲取進程ID 

pid在哪里?在你當前task_struct的標識符中。

所以我們調用getpid,本質是讓操作系統把當前進程的,從PCB把我的pid給拷貝出來,讓用戶看到自己的ID是什么。

  • 只要是一個進程,就必然有自己的ID信息,所有只要有ID,我們就能證明這是一個進程。

pid_t是系統提供的,不是C語言的double這些,但Linux也是由C語言寫的,這pid_t雖然是個系統級的類型,但它其實就是個int。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{printf("pid: %d\n", getpid());printf("ppid: %d\n", getppid());return 0;
}
3-6終止進程的方法

1.ctrl+c是殺掉進程的!

2.輸入命令:kill -9 +PID值(-9是一個信號編號)
在這里插入圖片描述
每一次啟動同一個進程,pid的值不同是很正常的;

我們運行的所有的命令,在系統里都是進程。只不過ls運行特別快,一啟動就退出;只不過top命令一啟動不退出,需要手動q來退出。

在Linux系統里,我們用戶是以進程的方式,來反問操作系統。把用戶看做一名老師,操作系統是一名學生,老師給學生布置任務,讓學生去完成,可以布置很多任務,所以我們一般把進程也叫任務。所以PCB在Linux里,它叫做task.

3-7查看一下pid24747當前目錄里的所有屬性

在這里插入圖片描述
在這里面,我們來重點了解一下exe和cwd:

1.exe:進程對應的可執行文件的絕對路徑+我的數據名

要是刪掉這個路徑,并不影響進程,因為你刪掉的是磁盤上的文件,而進程啟動時,這個程序的拷貝已經在內存了,所以刪掉并不直接影響這個進程,當然后面可能會有影響,后面再說。這充分證明了,我們自己代碼已經從磁盤拷貝到內存了,所以我這個進程還在運行。

但我們再查找一次,這個路徑就開始閃爍變紅:它告訴我們進程雖然還在,但他對應的可執行程序已經deleted。
在這里插入圖片描述
在這里插入圖片描述

  1. cwd 即 current work dir (當前工作目錄),會保存一個路徑,該路徑就是當前程序所在路徑。

在 C 語言中使用 fopen 函數創建文件,如 fopen("/a/b/c/d.txt","w"); fopen("d.txt","w"); 時,若 fopen 要新建文件,對于像 fopen("d.txt","w"); 這種不帶完整路徑的情況,文件會在當前進程的當前路徑下創建。

什么叫做當前路徑呢?也就是說為什么fopen新建一個不帶路徑的文件,它就在你的那個指定路徑下新建這個文件呢?

所謂當前路徑,是因為進程在啟動時會記錄下自身的當前路徑。 fopen 是進程內部的代碼,執行 fopen 時,傳入文件名后, fopen 內部會獲取當前的工作路徑,并將指定的文件名拼接到該路徑后面,所以新建的文件就在當前路徑下了。

3-8如何更改路徑

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

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{chdir("/home/LD");fopen("hello.txt","a");while(1){sleep(1);printf("我是一個進程!,我的pid:%d\n",getpid());}
}

在進程啟動時,先把自己的當前路徑改一下,改完之后再創建文件。

getppid
pid_t getppid(void);//獲取父進程ID

在Linux系統中,所有進程皆由其父進程創建,呈現單親繁殖的特點,不存在“母進程”這一概念。每個子進程都由對應的父進程生成,并且一個父進程能夠創建多個子進程。同時,父進程本身也有自己的父進程。基于這種進程間的創建關系,Linux中所有進程構成了類似樹狀的結構,故而也被稱作進程樹。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{while(1){sleep(1);printf("我是一個進程!,我的pid:%d,我的父進程id:%d\n",getpid(),getppid());}
}
我是一個進程 !,我的pid: 23421,我的父進程id: 21817
我是一個進程 !,我的pid: 23421,我的父進程id: 21817
我是一個進程 !,我的pid: 23421,我的父進程id: 21817
^C
[root@VM-8-2-centos lesson4]# ./myprocess
我是一個進程 !,我的pid: 23590,我的父進程id: 21817
我是一個進程 !,我的pid: 23590,我的父進程id: 21817
^C
[root@VM-8-2-centos lesson4]# ./myprocess
我是一個進程 !,我的pid: 23611,我的父進程id: 21817
我是一個進程 !,我的pid: 23611,我的父進程id: 21817
^C

我的pid每次啟動都會變化,這是正常的,它是一個遞增的一個值,其實你每次啟動你的進程都是向系統里重新加載。

父進程ID是不變的?那父進程是誰呢?

[root@VM-8-2-centos ~]# ps ajx | head -1 && ps axj | grep 21817 | grep -v grepPPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
21752 21817 21817 21817 pts/0    25397 Ss       0   0:00 -bash

我們查到的進程是一個bash,也就是說我自己的程序在啟動時,每一次啟動我的父進程都是bash,bash是什么呢?

bash——命令解釋器!

1.命令行解釋器(老板):bash本質是一個進程!

2.老板和實習生!

知識點:我們每次登陸我們的云服務器時,操作系統會給每一個登錄用戶分配一個bash!
其中bash前的-,表示是遠程登錄的。

那么下面的一串是什么?

[root@VM-8-2-centos lesson4]# 

這是bash打出來的一個字符串。

為什么光標就卡在那里不動了?

因為bash也是C語言寫的,我們可以想到之前寫printf,scanf的時候,一printf它就可以把字符串打印出來,一scanf它就卡在那里了,所以我們命令行輸入的所有命令都是喂給了對應的bash,以字符串交給bash,bash拿到命令就可以做分析了。

一個進程比如bash,他是怎么做到可以創建一個子進程呢?

代碼創建子進程的方式!

3-7通過系統調用創建進程——fork初識
  • man fork 認識fork
    在這里插入圖片描述
  • fork是一個系統調用,它的作用就是創建一個子進程。
    在這里插入圖片描述
    fork有創建了一個進程,那么我們一會將看到,第二個printf將執行兩次,但是打印的getpid()的值應該是不一樣的,因為一個是父進程它自己,一個是新創建的子進程。
    在這里插入圖片描述
    原理:進程=PCB(task struct)+自己的代碼和數據!

創建子進程時,操作系統會為其創建一個進程控制塊(PCB),本質是拷貝父進程的PCB 。父進程的PCB指向自身的代碼和數據,子進程創建后,默認也指向父進程的代碼和數據。由于此時沒有新程序加載,子進程沒有獨立的代碼和數據,會共享父進程的代碼和數據,在被調度執行時,會執行父進程后續的代碼。

我們執行下面命令來看一下fork的返回值:

man fork
/return val

在這里插入圖片描述
所以fork會有兩個返回值嗎??是的!!

我們要是想要父子進程未來執行不同得代碼邏輯!要怎么辦呢?

fork 之后通常要用 if 進行分流
在這里插入圖片描述
在這里插入圖片描述

fork 函數被調用后,系統會復制父進程的地址空間等資源來創建子進程,此時父子進程共享代碼段。之所以會出現子進程返回值為0,父進程返回值大于0(子進程ID),進而進入不同執行流。

疑問:
1.為什么fork給父子返回各自的不同返回值?為什么給子進程返回0,給父進程返回子進程對應的pid?

主要原因是父:子=1:n。父進程可能有多個孩子,所以一定要把子進程的pid返回給父進程,因為父進程要通過不同的pid,來區分它不同的子進程,而子進程就不需要獲得父進程的pid,因為它已經能獲得getppid了。

2.為什么一個函數會返回兩次?
一個函數運行到return XX了,它的核心功能已經做完了。
fork函數它本質是一個系統調用,它被調用時就會進入fork函數。在fork函數中,進行申請新的PCB,拷貝父PCB給子進程,子PCB放入進程list,甚至放入調度隊列中!(這時子進程已經被創建,甚至被調度了!)。
之后執行return id; return 是語句嗎?是的!所以實際上,在fork函數內部它在進行執行時,執行到return的時候就已經共享了,所以父進程會執行,子進程也會執行。所以return被返回兩次。

在這里插入圖片描述

3.為什么一個變量,即等于0,又大于0?導致if else同時成立?

關于變量看似矛盾的情況:不存在一個變量既等于0又大于0。在父子進程中,因進程獨立性,父進程掛了不影響子進程正常運行。

父子進程的數據關系:父子進程間數據初始是共享的,當任何一方要修改數據時,操作系統采用寫時拷貝技術,會在底層拷貝一份數據讓目標進程修改,如子進程寫數據時,父進程訪問舊數據,子進程訪問新拷貝的數據。
父子進程獨立性的實現:
一是數據結構獨立,因為數據與內存結構相關;
二是代碼共享,數據通過寫時拷貝方式各自私有一份,即父子進程代碼共享,數據各自開辟空間私有。

之后的在虛擬地址空間展現講。

在這里插入圖片描述
在這里插入圖片描述
圖片上,子進程不管怎么改,父進程都是100.

在這里插入圖片描述

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

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

相關文章

觀察者模式 (Observer Pattern)

觀察者模式(Observer Pattern)是一種行為型設計模式。它定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。當主題對象的狀態發生變化時,會自動通知所有觀察者對象,使它們能夠自動更新自己的狀態。 一、基礎 1. 意圖 核心目的:定義對象間的一種一對…

Network.framework 的引入,不是為了取代 URLSession

Network.framework 的引入&#xff0c;不是為了取代 URLSession 如果你感覺 Network.framework 的引入, 可能是為了取代 URLSession, 那你就大錯特錯了&#xff01;這里需要非常準確地區分一下&#xff1a; &#x1f535; Network.framework 不是為了取代 URLSession。 &…

Redis 數據分片三大方案深度解析與 Java 實戰

Redis 數據分片是將數據分散存儲在多個 Redis 實例上的技術&#xff0c;以解決單個 Redis 實例在存儲容量、性能和可用性上的限制。常見的 Redis 數據分片方案包括客戶端分片、代理分片和Redis Cluster&#xff08;集群分片&#xff09;&#xff0c;以下為你詳細介紹&#xff1…

FreeBSD可以不經過windows服務器訪問windows機器上的共享文件嗎?

答案是&#xff1a;當然可以&#xff01; 使用sharity-light 軟件 可以使用sharity-light 軟件&#xff0c;直接不用安裝samba等軟件&#xff0c;直接訪問windows機器上的共享文件。 但是可惜的是&#xff0c;sharity-light在FreeBSD的ports里棄用了。看來是從FreeBSD 8 就開…

主流 LLM 部署框架

主流 LLM 部署框架 框架主要特點適用場景vLLM- 超快推理&#xff08;高吞吐&#xff09; - 動態批處理 - 支持 HuggingFace Transformer - 支持 PagedAttention高并發、低延遲在線推理TGI (Text Generation Inference)- Huggingface官方出品 - 多模型管理 - 支持動態量化 - 支持…

在 Vue 3 setup() 函數中使用 TypeScript 處理 null 和 undefined 的最佳實踐

在 Vue 3 中使用 setup() 函數和 TypeScript 時&#xff0c;null 和 undefined 是兩個需要特別關注的類型。雖然它們看起來都表示“沒有值”&#xff0c;但它們在 JavaScript 和 TypeScript 中有著不同的含義和使用場景。如果不小心處理它們&#xff0c;可能會導致潛在的 bug 或…

在 UniApp 中獲取當前頁面地址

在 UniApp 中獲取當前頁面地址&#xff0c;可以通過以下步驟實現&#xff1a; 方法說明&#xff1a; 獲取當前頁面實例&#xff1a;使用 getCurrentPages() 獲取頁面棧數組&#xff0c;最后一個元素即為當前頁面實例。 提取頁面路徑和參數&#xff1a;從頁面實例的 route 屬性…

【華為】防火墻雙擊熱備-之-主備模式-單外網線路-分享

FW1和FW2的業務接口都工作在三層&#xff0c;上行連接二層交換機。上行交換機連接運營商的接入點&#xff0c;運營商為企業分配的IP地址為100.100.100.2。現在希望FW1和FW2以主備備份方式工作。正常情況下&#xff0c;流量通過FW1轉發&#xff1b;當FW1出現故障時&#xff0c;流…

crossOriginLoading使用說明

1. 說明 此配置用于控制 Webpack 動態加載的代碼塊&#xff08;chunk&#xff09;&#xff08;例如代碼分割或懶加載的模塊&#xff09;在跨域&#xff08;不同域名&#xff09;加載時的行為。它通過為動態生成的 <script>標簽添加 crossorigin 屬性&#xff0c;確保符合…

windows中安裝VMware Workstation Pro虛擬機和ubuntu

目錄 一、安裝 VMware Workstation Pro 虛擬機 1、官網下載VMware Workstation Pro 1.1 選中 "VMware Workstation Pro for PC" 的 "DOWNLOAD NOW" 1.2 跳轉到broadcom登錄頁面 1.3 注冊賬號 1.4 輸入給郵箱收到的驗證碼信息&#xff0c;然后點擊”Verify…

如何快速輕松地恢復未保存的 Word 文檔:簡短指南

文字處理器已經存在了幾十年&#xff0c;其中許多已經變得非常擅長防止問題。丟失未保存的數據是一個常見問題&#xff0c;因此辦公軟件通常帶有恢復文件的方法。在本文中&#xff0c;我們將介紹如何恢復 Word 文檔&#xff0c;即使您尚未保存它。 確保數據安全的最佳方法是保…

JavaScript原生實現簡單虛擬列表(列表不定高)

本文首發在我的個人博客上&#xff1a;JavaScript原生實現簡單虛擬列表(列表不定高)https://www.brandhuang.com/article/1745637125513 前言 之前實現了一個定高版本的虛擬列表&#xff0c;今天在定高版本的基礎上稍作調整&#xff0c;來實現不定高版本&#xff0c;之前的版本…

redis數據類型-位域bitfield

redis數據類型-位域bitfield 文檔 redis單機安裝redis常用的五種數據類型redis數據類型-位圖bitmapredis數據類型-基數統計HyperLogLogredis數據類型-地理空間GEOredis數據類型-流Stream 官方文檔 官網操作命令指南頁面&#xff1a;https://redis.io/docs/latest/commands/…

pandas讀取MySQL中的數據

使用pandas讀取MySQL中的數據 1、導入庫 pip install pandas pip install sqlalchemy2、示例代碼 # -*- coding: utf-8 -*-import pandas as pd import re from sqlalchemy import create_engine# 清洗文本 def clean_text(text):text

MyBatis緩存配置的完整示例,包含一級緩存、二級緩存、自定義緩存策略等核心場景,并附詳細注釋和總結表格

以下是MyBatis緩存配置的完整示例&#xff0c;包含一級緩存、二級緩存、自定義緩存策略等核心場景&#xff0c;并附詳細注釋和總結表格&#xff1a; 1. 一級緩存&#xff08;默認開啟&#xff09; // 使用同一SqlSession執行兩次查詢&#xff0c;自動命中一級緩存 try (SqlSe…

深入解析 C++17 中的std::variant與std::visit:從原理到實踐

引言 什么是std::variant 在 C17 之前&#xff0c;如果你想在一個變量中存儲多種可能的類型&#xff0c;通常會使用 union 或 void* 指針。然而&#xff0c;這些方法都有明顯的缺點。 使用 union 時&#xff0c;類型信息會丟失&#xff0c;使得代碼容易出錯。 void* 指針則需…

Dijkstra算法對比圖神經網絡(GNN)

什么是AI模型? AI模型(人工智能模型)是一類模仿人類智能行為的數學模型或算法。它們通過從大量數據中學習,識別模式、做出預測或決策。常見的AI模型包括機器學習模型(如決策樹、神經網絡、支持向量機)和深度學習模型(如卷積神經網絡CNN、循環神經網絡RNN)。簡單來說,…

Yarn 安裝與使用教程

Yarn 安裝與使用教程 Yarn 是一個由 Facebook 開發的 JavaScript 包管理工具&#xff0c;它比傳統的 npm 更加高效、可靠&#xff0c;并且在性能上有所提升。Yarn 主要解決了 npm 安裝速度慢、并發性差、緩存機制不完善等問題&#xff0c;它提供了更快的安裝速度、更穩定的依賴…

Spring Boot 的配置加載順序

Spring Boot 的配置加載順序是“后來居上”——優先級高的配置源會覆蓋優先級低的配置源中的同名配置 覆蓋規則如下&#xff1a; 后加載的配置具有更高的優先級&#xff0c;會覆蓋先加載的配置。如果多個配置源中存在同名配置項&#xff0c;最終生效的是具有最高優先級的那個…

Git分支重命名與推送參數解析

這兩個參數的解釋如下&#xff1a; git branch -M master 中的 -M 參數 -M 是 --move --force 的組合簡寫&#xff0c;表示強制重命名當前分支為 master。如果當前分支已經存在名為 master 的分支&#xff0c;-M 會強制覆蓋它&#xff08;慎用&#xff0c;可能導致數據丟失&…