【Golang那些事】go1.22和1.23 更新重點及測評

好久沒有寫文章了,攢了一年的Golang版本特性的技術點以及踩過的坑,那就在新年第一篇的文章中做一個總結吧:

一、關于迭代器

(一)迭代器去掉了共享共享內存

一個經典的面試題

說到Golang經典的面試題,大家可能都刷到過很多,筆者這里也曾經收藏過幾個比較有意思的面試題,下面這個就是其中之一:

package mainimport "fmt"func main() {slice := []int{0, 1, 2, 3}mymap := make(map[int]*int)for index, value := range slice {mymap[index] = &value}for key, value := range mymap {fmt.Printf("map[%v]: %v\n", key, *value)}
}

上面的代碼輸出結果是什么?

看起來似乎比較簡單:

其實,在20230915時間之前,輸出的結果為:

map[3]=3
map[0]=3
map[1]=3
map[2]=3

因為for range創建了迭代對象每個元素的副本,而不是直接返回每個元素的引用,如果使用該值變量的地址作為指向每個元素的指針,就會導致錯誤,在迭代時,返回的變量是同一個迭代過程中根據切片依次賦值的變量,所以最終map中存儲的地址都是同一個變量的地址,而其值即為最后一次迭代中賦的值

是不是比較容易出錯

這里也確實讓廣大Golang開發者吐槽的地方,所以在golang1.22中,golang官方終于對這里出手了

請在此添加圖片描述

可以看到這里官方自己也定義為最常見的Go錯誤之一

官方吐槽自己也是可以!

參考資料:

https://antonz.org/go-1-22/

https://tip.golang.org/doc/go1.22

(二)迭代器的"For" loops may 支持整數

一個更方便寫測試用例的小功能

for i := range 10 {fmt.Print(10 - i, " ")
}
fmt.Println()
fmt.Println("go1.22 has lift-off!")

這個在1.22中進行了添加

參考資料:

https://antonz.org/go-1-22/

https://blog.csdn.net/Wksycxy/article/details/136770738

https://tip.golang.org/ref/spec#For_range

(三)迭代器與range的結合

一致的迭代器形式

歷史背景:

Russ發現Go標準庫中有很多庫(如上截圖)中都有迭代器的實現,但形式不統一,沒有標準的“實現路徑”,各自為戰。這與Go面向工程的目標有悖,現狀阻礙了大型Go代碼庫中的代碼遷移。因此,Go團隊希望給大家帶來一致的迭代器形式,具體來說就是允許for range支持對一定類型函數值(function value)進行迭代,即range over func。

2024年2月,iterator以試驗特性被Go 1.22版本引入,通過GOEXPERIMENT=rangefunc可以開啟range-over-func特性以及使用iter包。
在golang.org/x/exp下面,Go團隊還提議維護一個xiter包,這個包內提供了用于組合iterator的基本適配器(adapter),不過目前該xiter包依舊處于proposal狀態,尚未落地。
2024年8月,iterator將伴隨Go 1.23版本正式落地,現在我們可以通過Go playground在線體驗iterator,當然你也可以安裝Go tip版本或Go 1.23的rc版在本地體驗。

終于在1.23落地了

請在此添加圖片描述

這意味著很多用迭代器的地方可以通過range for的形式顯示調用

var m sync.Mapm.Store("alice", 11)
m.Store("bob", 12)
m.Store("cindy", 13)// 1.22
m.Range(func(key, value any) bool {fmt.Println(key, value)return true
})// 1.23
for key, val := range m.Range {fmt.Println(key, val)
}

可以看到后面這種方式更加的簡潔

還有一些比較簡潔的操作可以參考:

https://antonz.org/go-1-23/#timer-changes

二、關于切片

(一)增加了連接函數,順道在切片修改的函數做了健壯性處理

用好slices是golang開發的一個重要點

關于新的連接函數

s1 := []int{1, 2}
s2 := []int{3, 4}
s3 := []int{5, 6}
res := slices.Concat(s1, s2, s3)
fmt.Println(res)

關于delete函數

請在此添加圖片描述

關于Compact和Replace函數

請在此添加圖片描述

關于insert函數,更加的強Schema

如果參數 i 超出范圍,Insert函數會報panic。

請在此添加圖片描述

參考資料:

https://antonz.org/go-1-22/

(二)關于slices.Repeat

用法比較簡單:

s := []int{1, 2}
r := slices.Repeat(s, 3)
fmt.Println(r)

輸出為:

1 2 1 2 1 2

三、關于隨機數

(一)新的隨機庫

1.22版本提供了一個新的庫math/rand/v2

math/rand/v2 并不是 math/rand的升級

這里可以說一說隨機數的歷史淵源

其實大家對math/rand不是那么滿意。
2017年,#20661 中提到math/rand.Read和crypto/rand.Read相近,導致本來應該使用crypto/rand.Read的地方使用了math/rand.Read,導致了安全問題
2017年,#21835 中 Rob Pike 提議在Go 2中使用PCG Source。
2018年,#26263 中 Josh Bleecher Snyder 提議對math/rand進行徹底的重構。
2023年6月, Russ Cox基于先前的對math/rand的吐槽,以及和Rob Pike的討論,建立了一個討論(#60751),準備新建一個包math/rand/v2,重新設計和實現一個新的偽隨機數的庫討論也很熱烈,最后實現了一個提案#61716,這個提案最直接的動機是清理 math/rand 并解決其中許多懸而未決的問題,特別是使用過時生成器、緩慢的算法,以及與 crypto/rand.Read 的不幸沖突。
由于go module的支持版本v2、v3、…, Go 1.22中將會有一個新的包math/rand/v2,這個包將會是一個新的包,而不是math/rand的升級版本。這個包的目標是提供一個更好的偽隨機數生成器,它的 API 也更加簡單易用,同時一些檢查工具也能支持這個包,不會報錯。
看樣子,math/rand/v2將會是第一個在標準庫中建立v2版本的包,如果大家能夠接受,將來會有更多的包加入進來,比如sync/v2、encoding/json/v2等等。

信息來源:https://colobu.com/2023/12/24/new-math-rand-in-Go/

可以看到當一個庫的問題足夠多的時候,總會有優秀的工程師站出來,進行一波大的重構,解決歷史問題,這個也適用于官方代碼

這里一個簡單的結論,關于隨技術

1.考慮到安全避免被人預測的場景下,要使用crypto/rand 包。

2.其他的情況一般來說使用ath/rand/v2就夠了

參考資料:

https://antonz.org/go-1-22/

https://colobu.com/2023/12/24/new-math-rand-in-Go/

四、關于HTTP庫

(一)增加不同方法的Handle調用及URL模糊匹配能力

如果使用Gin等框架的話,其實這個能力已經有了,現在Go1.22版本也提供

官方表示,我也可以主動提供一些框架的能力,如果大家有想寫Web框架的話會更友好

###1.下面這里如果填寫了POST,則使用專門handler來處理

mux.HandleFunc("POST /items/create", func(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "POST item created")
})mux.HandleFunc("/items/create", func(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "item created")
}){// uses POST routeresp, _ := http.Post(server.URL+"/items/create", "text/plain", nil)body, _ := io.ReadAll(resp.Body)fmt.Println("POST /items/create:", string(body))resp.Body.Close()
}{// uses generic routeresp, _ := http.Get(server.URL+"/items/create")body, _ := io.ReadAll(resp.Body)fmt.Println("GET /items/create:", string(body))resp.Body.Close()
}

輸出的結果為:

POST /items/create: POST item created
GET /items/create: item created

###2.下面這里可以使用像:/items/{id}通配符的形式獲取參數

mux.HandleFunc("/items/{id}", func(w http.ResponseWriter, r *http.Request) {id := r.PathValue("id")fmt.Fprintf(w, "Item ID = %s", id)
})req, _ := http.NewRequest("GET", server.URL+"/items/12345", nil)
resp, _ := http.DefaultClient.Do(req)
body, _ := io.ReadAll(resp.Body)
fmt.Println("GET /items/12345:", string(body))
resp.Body.Close()

以 …結尾的通配符(如 /files/{path…})必須出現在模式的末尾,也可以獲取

mux.HandleFunc("/files/{path...}", func(w http.ResponseWriter, r *http.Request) {path := r.PathValue("path")fmt.Fprintf(w, "File path = %s", path)
})req, _ := http.NewRequest("GET", server.URL+"/files/a/b/c", nil)
resp, _ := http.DefaultClient.Do(req)
body, _ := io.ReadAll(resp.Body)
fmt.Println("GET /files/a/b/c:", string(body))
resp.Body.Close()

以 / 結尾的模式會一如既往地匹配所有將其作為前綴的路徑。要匹配包括尾部斜杠的確切模式,請以 {KaTeX parse error: Expected 'EOF', got '}' at position 1: }? 結尾,如 /exact/ma…}:

mux.HandleFunc("/exact/match/{$}", func(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "exact match")
})mux.HandleFunc("/exact/match/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "prefix match")
}){// exact matchreq, _ := http.NewRequest("GET", server.URL+"/exact/match/", nil)resp, _ := http.DefaultClient.Do(req)body, _ := io.ReadAll(resp.Body)fmt.Println("GET /exact/match/:", string(body))resp.Body.Close()
}{// prefix matchreq, _ := http.NewRequest("GET", server.URL+"/exact/match/123", nil)resp, _ := http.DefaultClient.Do(req)body, _ := io.ReadAll(resp.Body)fmt.Println("GET /exact/match/123:", string(body))resp.Body.Close()
}

這里有個細節:

**如果兩個模式在匹配的請求中重疊,則更具體的模式優先。**如果兩者都不更具體,則模式會發生沖突。此規則概括了原始優先規則,并維護了模式的注冊順序無關緊要的屬性。

###3.NewRequestWithContext

新的 NewRequestWithContext 方法創建具有上下文的傳入請求。

(二)增加Cookies的方法

如果使用Gin等框架的話,其實這個能力已經有了,現在Go1.23版本也提供

ParseCookie 函數

解析 Cookie 標頭值并返回在其中設置的所有 Cookie。由于相同的 Cookie 名稱可以多次出現,因此返回的 Value 可以包含給定鍵的多個值。

line := "session_id=abc123; dnt=1; lang=en; lang=de"
cookies, err := http.ParseCookie(line)
if err != nil {panic(err)
}
for _, cookie := range cookies {fmt.Printf("%s: %s\n", cookie.Name, cookie.Value)
}

ParseSetCookie 函數

解析 Set-Cookie 標頭值并返回 Cookie

line := "session_id=abc123; SameSite=None; Secure; Partitioned; Path=/; Domain=.example.com"
cookie, err := http.ParseSetCookie(line)
if err != nil {panic(err)
}
fmt.Println("Name:", cookie.Name)
fmt.Println("Value:", cookie.Value)
fmt.Println("Path:", cookie.Path)
fmt.Println("Domain:", cookie.Domain)
fmt.Println("Secure:", cookie.Secure)
fmt.Println("Partitioned:", cookie.Partitioned)

Request.CookiesNamed函數

檢索與給定名稱匹配的所有 Cookie

func handler(w http.ResponseWriter, r *http.Request) {cookies := r.CookiesNamed("session")if len(cookies) > 0 {fmt.Fprintf(w, "session cookie = %s", cookies[0].Value)} else {fmt.Fprint(w, "session cookie not found")}
}func main() {req := httptest.NewRequest("GET", "/", nil)req.AddCookie(&http.Cookie{Name: "session", Value: "abc123"})w := httptest.NewRecorder()handler(w, req)resp := w.Result()body, _ := io.ReadAll(resp.Body)fmt.Println(string(body))
}

五、關于計時器

(一)新的資源優化

1.23版本對計時器的資源使用做了優化

關于以下代碼

// go 1.22
type token struct{}func consumer(ctx context.Context, in <-chan token) {for {select {case <-in:// do stuffcase <-time.After(time.Hour):// log warningcase <-ctx.Done():return}}
}

會事實上導致廣義上的內存泄漏,即雖然有指針指向,但其實應用不在使用了

我們可以做個實驗:

編寫 100K 通道發送后的內存使用情況:

// go 1.22
func main() {ctx, cancel := context.WithCancel(context.Background())defer cancel()tokens := make(chan token)go consumer(ctx, tokens)memBefore := getAlloc()for range 100000 {tokens <- token{}}memAfter := getAlloc()memUsed := memAfter - memBeforefmt.Printf("Memory used: %d KB\n", memUsed/1024)
}

輸出結果為:

Memory used: 24325 KB

這是因為,time.After() 一旦調用了,該計時器在過期之前不會釋放,所以這里的內存都積壓了

而在 Go 1.23 中,不再被程序引用的 Timer和 Ticker立即符合垃圾回收的條件,即使它們的 Stop 方法尚未被調用。所以不會存在內存積壓問題

(二)關于reset的坑

看下面這段代碼:

// go 1.22
func main() {const timeout = 10 * time.Millisecondt := time.NewTimer(timeout)time.Sleep(20 * time.Millisecond)start := time.Now()t.Reset(timeout)<-t.Cfmt.Printf("Time elapsed: %dms\n", time.Since(start).Milliseconds())// expected: Time elapsed: 10ms// actual:   Time elapsed:  0ms
}

這里輸出為:

Time elapsed: 0ms

因為計時器超時時間設置為 10 毫秒。所以在我們等待 20ms 之后,它已經過期并向 t.C 通道發送了一個值。由于Reset 不重置channel,因此 <-t.C 不會阻塞并立即進行。所以第9行會直接執行,從而打印的時間就是當時的時間(此外,由于 Reset函數重啟了計時器,在 10ms 后t.C還會收到一個過期的信號)

Go 1.23 中修復說明:

The timer channel associated with a Timer or Ticker is now unbuffered, with capacity 0. The main effect of this change is that Go now guarantees that for any call to a Reset or Stop method, no stale values prepared before that call will be sent or received after the call.

也就是說通過無緩沖的方式解決了通道重制的問題

詳細可以參考:

https://antonz.org/go-1-23/#timer-changes

六、關于“字符串駐留”

(一)unique 包

字符串去重

Go 1.23 標準庫引入了一個名為 unique 的新包,旨在實現可比較值的規范化。簡而言之,該包允許你對值進行去重,使其指向單個規范的唯一副本,并在底層有效管理這些規范副本

這里寫一個比較簡單的字符串駐留的函數

var internPool map[string]string// Intern 返回一個與 s 相等的字符串,但該字符串可能與之前傳遞給 Intern 的字符串共享存儲空間。
func Intern(s string) string {pooled, ok := internPool[s]if !ok {// 克隆字符串,以防它是某個更大的字符串的一部分。// 如果正確使用字符串駐留,這種情況應該很少見。pooled = strings.Clone(s)internPool[pooled] = pooled}return pooled
}

當你構建許多可能是重復的字符串時(例如在解析文本格式時),這非常有用。

此實現非常簡單,在某些情況下效果很好,但它也存在一些問題:

它永遠不會從池中刪除字符串。

多個 goroutine 無法安全地同時使用它。

它僅適用于字符串,即使該想法非常通用。

此實現還有一個錯失的機會,而且很微妙。在底層,字符串是由指針和長度組成的不可變結構。比較兩個字符串時,如果指針不相等,則必須比較它們的內容以確定是否相等。但如果我們知道兩個字符串是規范化的,那么只需檢查它們的指針就_足夠_了。

新的 unique 包引入了一個名為 Make 的函數,類似于 Intern

它的工作方式與 Intern 大致相同。在內部,它也使用全局映射(一個快速的泛型并發映射),Make 在該映射中查找提供的值。但它也與 Intern 有兩個重要區別。首先,它接受任何可比較類型的值。其次,它返回一個包裝值,即 HandleT,可以從中檢索規范值。

HandleT 是設計的關鍵。HandleT 具有以下屬性:當且僅當用于創建它們的_值_相等時,兩個 HandleT _值_才相等。更重要的是,比較兩個 HandleT 值的成本很低:它歸結為指針比較。與比較兩個長字符串相比,這要便宜一個數量級!

到目前為止,這在普通的 Go 代碼中都能做到。

關于使用

使用這里筆者找到了兩個例子,不過筆者覺得后續可以再找一些

// Addr 表示 IPv4 或 IPv6 地址(帶或不帶范圍尋址區域),類似于 net.IP 或 net.IPAddr。
type Addr struct {// 其他不相關的未導出字段...// 有關地址的詳細信息,匯總在一起并進行規范化。z unique.Handle[addrDetail]
}// addrDetail 指示地址是 IPv4 還是 IPv6,如果是 IPv6,則指定地址的區域名稱。
type addrDetail struct {isV6   bool   // IPv4 為 false,IPv6 為 true。zoneV6 string // 如果 IsV6 為 true,則可能 != ""。
}var z6noz = unique.Make(addrDetail{isV6: true})// WithZone 返回一個與 ip 相同但具有提供的區域的 IP。如果區域為空,則刪除該區域。如果 ip 是 IPv4 地址,則 WithZone 是無操作的,并返回未更改的 ip。
func (ip Addr) WithZone(zone string) Addr {if !ip.Is6() {return ip}if zone == "" {ip.z = z6nozreturn ip}ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone})return ip
}

由于許多 IP 地址可能使用相同的區域,并且此區域是其身份的一部分,因此對它們進行規范化非常有意義。區域的去重減少了每個 netip.Addr 的平均內存占用量,而它們被規范化的事實意味著 netip.Addr 值的比較效率更高,因為比較區域名稱變成了簡單的指針比較。
具體可以參考:https://k8scat.com/posts/go/go-1.23-unique/

另一個例子:

假設我們有一個隨機詞生成器:

我們用它從 100 個單詞的詞匯表中生成 10,000 個單詞:

// wordGen returns a generator of random words of length wordLen
// from a set of nDistinct unique words.
func wordGen(nDistinct, wordLen int) func() string {vocab := make([]string, nDistinct)for i := range nDistinct {word := randomString(wordLen)vocab[i] = word}return func() string {word := vocab[rand.Intn(nDistinct)]return strings.Clone(word)}
}// randomString returns a random string of length n.
func randomString(n int) string {// omitted for brevity
}var words []stringfunc main() {const nWords = 10000const nDistinct = 100const wordLen = 40generate := wordGen(nDistinct, wordLen)memBefore := getAlloc()// store wordswords = make([]string, nWords)for i := range nWords {words[i] = generate()}memAfter := getAlloc()memUsed := memAfter - memBeforefmt.Printf("Memory used: %d KB\n", memUsed/1024)
}

運行結果為:

Memory used: 622 KB

而如果用unique

var words []unique.Handle[string]func main() {const nWords = 10000const nDistinct = 100const wordLen = 40generate := wordGen(nDistinct, wordLen)memBefore := getAlloc()// store word handleswords = make([]unique.Handle[string], nWords)for i := range nWords {words[i] = unique.Make(generate())}memAfter := getAlloc()memUsed := memAfter - memBeforefmt.Printf("Memory used: %d KB\n", memUsed/1024)
}

結果為:

Memory used: 96 KB

具體可以參考:https://antonz.org/go-1-23/#timer-changes

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

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

相關文章

python力扣438.找到字符串中所有字母異位詞

給定兩個字符串 s 和 p&#xff0c;找到 s 中所有 p 的 異位詞的子串&#xff0c;返回這些子串的起始索引。不考慮答案輸出的順序。 示例 1: 輸入: s “cbaebabacd”, p “abc” 輸出: [0,6] 解釋: 起始索引等于 0 的子串是 “cba”, 它是"abc" 的異位詞。 起始索引…

【大模型實戰篇】使用GPTQ量化QwQ-32B微調后的推理模型

1. 量化背景 之所以做量化&#xff0c;就是希望在現有的硬件條件下&#xff0c;提升性能。量化能將模型權重從高精度&#xff08;如FP32&#xff09;轉換為低精度&#xff08;如INT8/FP16&#xff09;&#xff0c;內存占用可減少50%~75%。低精度運算&#xff08;如INT8&#xf…

【MySQL】架構

MySQL架構 和其它數據庫相比&#xff0c;MySQL有點與眾不同&#xff0c;它的架構可以在多種不同場景中應用并發揮良好作用。主要體現在存儲引擎的架構上&#xff0c;插件式的存儲引擎架構將查詢處理和其它的系統任務以及數據的存儲提取相分離。這種架構可以根據業務的需求和實…

JavaScript 金額運算精度丟失問題及解決方案

JavaScript 金額運算精度丟失問題及解決方案 1. 前言2. 為什么 JavaScript 計算金額會精度丟失&#xff1f;2.1 JavaScript 使用 IEEE 754 雙精度浮點數2.2 浮點運算錯誤示例**錯誤示例 1&#xff1a;0.1 0.2 ≠ 0.3****錯誤示例 2&#xff1a;浮點乘法精度問題** 3. 解決方案…

Docker安裝,并pullMySQL和redis

卸載原Docker 您的 Linux 發行版可能提供非官方的 Docker 軟件包&#xff0c;這可能與 Docker 提供的官方軟件包沖突。在安裝 Docker Engine 正式版之前&#xff0c;您必須先卸載這些軟件包。 sudo dnf remove docker \ docker-client \ docker-client-latest \ docker-common…

國內首臺太空采礦機器人亮相,宇宙資源開發邁入新階段

隨著地球資源的日益枯竭&#xff0c;人類將目光投向了浩瀚的宇宙。太空采礦作為一項前沿科技&#xff0c;正逐步從科幻走向現實。近日&#xff0c;中國礦業大學成功研制出國內首臺太空采礦機器人&#xff0c;標志著我國在太空資源開發領域邁出了重要一步。 太空采礦并非新鮮概念…

簡介PyCDE:Python CIRCT Design Entry

簡介PyCDE&#xff1a;Python CIRCT Design Entry 引言 在硬件設計和驗證領域&#xff0c;隨著設計復雜性的增加&#xff0c;傳統的方法往往難以滿足現代設計的需求。PyCDE&#xff08;Python CIRCT Design Entry&#xff09;作為CIRCT項目的一部分&#xff0c;旨在為硬件設計…

市場熱點復盤20240319

以下是對當前市場熱點板塊的分析總結&#xff0c;按邏輯分類如下&#xff1a; 一、機器人產業鏈核心標的 1. 減速器與核心部件 襄陽軸承&#xff1a;直接受益人形機器人減速器軸承需求&#xff0c;技術國內領先。金帝股份&#xff1a;聚焦機器人手指關節諧波減速機保持架&am…

目標檢測——清洗數據

清洗VOC格式數據集代碼示例 import os import xml.etree.ElementTree as ETdef process_annotations(image_folder, annotation_folder):# 遍歷標簽文件夾中的所有XML文件for xml_file in os.listdir(annotation_folder):if not xml_file.endswith(.xml):continuexml_path os…

Kubeasz工具快速部署K8Sv1.27版本集群(二進制方式)

文章目錄 一、基本信息二、服務器初始化操作三、使用Kubeasz部署K8S集群四、驗證集群 一、基本信息 1、部署需要滿足前提條件&#xff1a; 注意1&#xff1a;確保各節點時區設置一致、時間同步&#xff1b;注意2&#xff1a;確保在干凈的系統上開始安裝&#xff1b;注意3&…

RG-S3760應用協議配置

RG-S3760應用協議配置 1. dhcp 服務配置 提問&#xff1a;如何在設備上開啟dhcp 服務&#xff0c;讓不同VLAN 下的電腦獲得相應的IP 地址&#xff1f; 回答&#xff1a; 步驟一&#xff1a;配置VLAN 網關IP 地址&#xff0c;及將相關端口劃入相應的VLAN 中 S3760#con t S…

Java 文件和IO流基礎(生動形象版)

系列文章目錄 Java文件和IO流基礎部分 文件VSIO流 文章目錄 系列文章目錄前言一、文件的定義和理解&#xff1a; 1.專業定義&#xff1a; 2.文件系統和路徑&#xff1a; 二、IO流的定義和分類 1.定義&#xff1a;2.流的分類&#xff1a;修飾器模式的核心作用&#xff1a;基礎結…

Linux驅動學習筆記(四)

高級字符設備進階 1.一個完整的IO過程包含以下幾個步驟&#xff1a;1應用程序向操作系統發起IO調用請求(系統調用)&#xff1b;2操作系統準備數據&#xff0c;把IO設備的數據加載到內核緩沖區&#xff1b;3操作系統拷貝數據&#xff0c;把內核緩沖區的數據從內核空間拷貝到應用…

el-table的行向上移動向下移動,刪除選定行

<template><el-table :data"tableData" border style"width: 100%"><!-- 其他列 --><el-table-column label"ID"><template slot-scope"scope">{{ scope.$index }}</template></el-table-colu…

人工智能之數學基礎:矩陣的降維

本文重點 在現實世界中,我們經常會遇到高維數據。例如,圖像數據通常具有很高的維度,每個像素點都可以看作是一個維度。高維數據不僅會帶來計算和存儲上的困難,還可能會導致 “維數災難”,即隨著維度的增加,數據的稀疏性和噪聲也會增加,從而影響數據分析的效果。因此,我…

2025年,電腦還需要分區嗎?

隨著2025年的到來&#xff0c;電腦存儲空間已經不像以前那么金貴&#xff0c;固態硬盤&#xff08;SSD&#xff09;容量更大、速度更快&#xff0c;云存儲也成了日常標配。許多人開始質疑&#xff1a;電腦還需要像以前那樣分區嗎&#xff1f; 一、分區到底是什么意思&#xff…

Springboot項目集成maven-assembly-plugin進行打包

通常我們將應用部署到服務器的某個目錄下&#xff0c;一般情況下我們會提供像target&#xff08;存放應用jar包&#xff09;&#xff0c;bin&#xff08;項目啟動/停止腳本&#xff09;&#xff0c;config&#xff08;項目配置文件&#xff09;&#xff0c;logs&#xff08;項目…

CSS3 基礎布局技術與響應式設計

1. CSS3 基礎與布局技術 1.1 Flexbox 布局 Flexbox 是一種一維布局模型&#xff0c;適合用于在一個方向上&#xff08;行或列&#xff09;排列元素。 基本概念&#xff1a; 容器&#xff08;Container&#xff09;&#xff1a;應用 display: flex; 的元素。項目&#xff08…

鴻蒙NEXT項目實戰-百得知識庫01

代碼倉地址&#xff0c;大家記得點個star IbestKnowTeach: 百得知識庫基于鴻蒙NEXT穩定版實現的一款企業級開發項目案例。 本案例涉及到多個鴻蒙相關技術知識點&#xff1a; 1、布局 2、配置文件 3、組件的封裝和使用 4、路由的使用 5、請求響應攔截器的封裝 6、位置服務 7、三…

【DeepSeek應用】本地部署deepseek模型后,如何在vscode中調用該模型進行代碼撰寫,檢視和優化?

若已成功在本地部署了 DeepSeek 模型(例如通過 vscode-llm、ollama 或私有 API 服務),在 VS Code 中調用本地模型進行代碼撰寫、檢視和優化的完整流程如下: 1. 準備工作:確認本地模型服務狀態 模型服務類型: 若使用 HTTP API 服務(如 FastAPI/Flask 封裝),假設服務地址…