MIT 6.824學習心得(2) 淺談多線程和RPC

? ? ? ? 上篇文章中我們簡單介紹了分布式系統的設計思想以及簡單性質,之后用一定篇幅簡要介紹了MapReduce這個經典的分布式計算框架的大致工作原理,相信朋友們已經對此有了最基本的理解。在現實場景中,分布式系統的設計初衷是為了解決并發問題,能夠承受單機系統所不能承受的流量負擔,并充分利用計算機集群的硬件資源。同時,既然會利用到計算機集群,那么集群間通信也是一個不可忽略的討論關鍵吧。由此,本文會著重討論分布式系統中的并發問題以及通信問題。在介紹本文內容之前,需要提示朋友們:如果想要更好的理解本文中提到的知識點,需要有一定的操作系統和網絡相關的知識,否則可能會略顯吃力。

? ? ? ? 說到設計分布式系統,那么相信一定有朋友們會聯想到golang這門編程語言。golang是由Google公司與2007年開始設計,2009年正式發布開源的一門主要適配后端開發的編程語言。golang語言的設計初衷是在保證高性能的同時,提高程序員的開發效率,適合構建高并發、高可用的后端系統。相比于C/C++,golang的語法更加簡潔清晰,刪去了部分冗余特性,同時支持垃圾回收(GC)和手動內存優化,相比C/C++又不失太多性能。最重要的是golang有相對比較完善的內置并發機制。這也是golang語言在現代應用廣泛的主要原因,常應用于云原生與微服務架構的項目開發,構建高并發的web服務,DevOps工具開發,網絡爬蟲,區塊鏈,構建日志系統,數據處理等多個領域。由于篇幅有限,本文不再贅述go語言的基礎語法。

一.golang與并發編程

(一)并發與并行

? ? ? ? 相信學過操作系統相關知識的朋友一定對進程線程這兩個名詞不會陌生。這里如果讓我去介紹進程線程,我可能真的想不起來那些長篇大論晦澀難懂的八股,背那些東西也挺沒意思的,除了應付考試也沒有什么用。我個人對于進程和線程的理解是:無論是進程還是線程,本質上都是程序運行的載體。進程擁有獨立的內存地址空間,而線程則是進程中最小的執行單元。多個線程可共享同一個進程的內存地址空間,一個進程可以包含很多個線程。

? ? ? ? 假如我們需要并發處理一個任務,那就有多進程多線程兩種處理策略。可以把多進程策略聯想為讓不同的公司處理這個問題,每家公司都有獨立的辦公區域(內存空間),彼此互不干擾。可以把多線程策略聯想為讓同一家公司內部的不同員工處理這個問題,它們共享辦公區域(內存空間),配合效率更高,但是也需要進行協調避免沖突。

? ? ? ? 處理一個大型任務通常有兩個最基本的優化思路。首先是并發I/O。我們可以通過上面提到的兩種策略實現并發處理,而golang語言則內置了一種更加輕量級的用戶態線程-goroutine(協程)來解決并發問題,允許不同的goroutine各自處理任務,我們后面會進行介紹。另外我們可以利用多核并行。現在的CPU大多數都擁有多個核心,我們完全可以利用多個CPU核心同時處理不同任務來提升任務的處理效率。在實際開發中,服務端開發者通常會結合使用上面這兩種優化思路,在使用多進/線程提高并發量的同時,通過盡可能使用多核并行充分利用CPU中大量核心所產生的性能。

????????這里可能會有一些不了解操作系統基本知識的朋友會疑惑,什么是并發,什么又是并行?這確實是初學者非常容易混淆的兩個概念。并行是指多個任務在多個 CPU 核心上真正同時運行,彼此互不干擾。而并發則是多個任務在單個或多個核心上“交替執行”。操作系統通過時間片輪轉的方式快速在任務之間切換,雖然任意時刻每個核心只執行一個任務,但由于切換足夠快,在用戶看來就像是這些任務同時進行一樣。并發并不意味著真正的同時運行,而是一種在資源有限條件下的高效調度策略。總結一句話,并行關注的是“同時做多件事”,而并發關注的是“如何管理好多件事”。

? ? ? ? 除此之外,還有另外一種處理并發的高效方法,即異步編程,也稱事件驅動編程。它允許任務在等待某些操作完成期間,不阻塞當前線程而是掛起當前操作、繼續執行其他任務。其核心機制是單線程+事件循環。在 系統層面,異步編程往往依賴于 I/O 多路復用機制 來實現非阻塞的 I/O。而且開銷會比多進/線程小,規避了創建銷毀進/線程,以及上下文切換的成本。不過缺點是無法充分利用CPU的多核并行能力,比較適合I/O密集型任務。所以在選擇策略時,我們應重點關注當前任務屬于計算密集型任務,還是I/O密集型任務

(二)go如何支持并發

? ? ? ? 在前文的敘述中,我們有提到,golang內置了一種更加輕量級的線程-goroutine來解決并發問題。事實上,goroutine也只是對傳統操作系統線程的一種“用戶態封裝”,由 Go 運行時通過 GMP 模型來進行調度和管理,并非通過操作系統內核直接調度。關于GMP模型我們會單獨出文章來介紹,這是很多企業面試的常考題,我就有兩三次都被問到過與傳統線程相比,goroutine 創建和切換的成本非常低,占用資源極少,初始棧空間只有幾 KB(傳統操作系統線程大約是MB級別),可以輕松支持成千上萬個并發任務。開發者只需使用go關鍵字即可啟動一個新的并發任務,無需手動管理線程、鎖或上下文切換。總的來說,goroutine 就是 Go 并發能力的核心。除此之外,go內置了一系列非常使用的并發原語,這些原語我們會在后面穿插介紹。

? ? ? ? 處理并發問題主要有以下幾大挑戰。首先是如何處理共享數據。如果在一塊內存區域中存在一個共享的數據對象,多個線程在同時讀寫共享數據,線程的執行順序不確定,會造成數據的不一致,也就是會導致一系列并發安全相關的問題。同時,多線程也會引入資源競爭的問題。針對上述問題一個非常行之有效的方法便是引入同步機制,其中最常見的便是加互斥鎖。其次,golang的一大設計哲學是“并非通過共享內存實現通信,而是通過通信實現共享內存”。由此,作為開發者,goroutine之間的交互通信需要引起格外重視。go內置了線程安全的channel數據結構來實現gouroutine之間的通信,同時內置Waitgroup原語協調多個goroutine的執行。最后,Go語言也內置了檢測鎖競爭或者死鎖的工具,在編譯時加上-race標志,可以檢測數據競爭和一些潛在的鎖問題,這里需要注意-race并不是一種靜態檢測機制,即源碼層面的檢查,而是檢查當前程序的運行狀態。如果上面介紹的這些專有名詞沒有理解,沒關系,下面會給出具體的實例來幫助大家理解。

(三)多線程編程實例:簡單網絡爬蟲

? ? ? ? ?相信朋友們應該對“爬蟲”這個貌似挺火的詞匯不陌生。網絡爬蟲是一種自動訪問網頁并提取內容的程序。該程序從網頁URL開始,下載網頁內容并提取網頁中的鏈接,并不斷重復以上過程,在數據的采集,分析,監控等方面有顯著作用。我們往往不想重復抓取一個頁面,這對于網絡帶寬是很大的浪費,所以我們會采用布隆過濾器進行去重操作。在本文中將介紹兩種最常見的爬蟲程序的實現思路。

? ? ? ? 第一種思路是串行爬蟲,我們在網絡路徑圖中通過有效執行深度優先搜索(DFS),逐步訪問頁面,每抓取一個URL就啟動一個goroutine,維護一個map記錄已經爬取過的頁面實現去重,避免重復抓取。思路很簡單,示例代碼如下:

func Serial(url string,fetcher Fetcher,fetched map[string]bool){//去重邏輯if fetched[url]{return}fetched[url]=trueurls,err := fetcher.Fetch(url)if err != nil{return}//深度優先搜索邏輯,遞歸訪問頁面for _, u :=range urls{Serial(u,fetcher,fetched)}return
}

? ? ? ? 第二種思路是并行爬蟲。并行爬蟲有兩種實現方式。第一種是通過共享數據對象以及加鎖實現。在實現中我們使用了 sync.Mutex 來保護共享的 map[string]bool,用于記錄已經抓取過的 URL。這里可能需要解釋一下為什么要在for循環中使用閉包函數并傳入u,因為 range?循環中的變量 u是被復用的,而 閉包默認捕獲的是變量的引用地址,而不是值本身。這意味著當 goroutine 實際啟動執行時,外層循環可能已經更新了 u 的值,導致捕獲到的并不是我們期望的 URL。為了解決這個問題,我們在閉包函數中u 顯式作為參數傳入,確保每個 goroutine 拿到的都是對應循環當時的 u 值,從而保證抓取邏輯的正確性。而這段代碼中也使用到了WaitGroup原語,可以把它看成一個計數器:每啟動一個goroutine,執行Add(1),讓計數器+1。當這個goroutine完成任務時,執行Done(),讓計數器-1。主協程通過調用 Wait() 進入阻塞狀態,直到所有 goroutine 執行完畢、計數器歸零為止。在實際爬蟲程序的設計中,我們往往還需要利用協程池來控制并發goroutine數量,防止資源耗盡。

? ? ? ? 說起閉包函數,我會想到一個非常有意思的問題。如果一個閉包函數引用了其外圍函數中的局部變量,而此時外圍函數已經 return,那么這個變量會發生什么?起初我會擔心:既然外圍函數已經返回,里面定義的局部變量理應隨著棧幀銷毀,那閉包函數所引用的變量是否會“懸空”?是否會導致運行時錯誤?答案是不會,Go 的編譯器在處理閉包時,會自動識別這種捕獲了外部局部變量的情況,并進行“逃逸分析”。當編譯器發現某個局部變量被閉包引用,并且閉包的生命周期可能超過當前函數時,它會將這個變量從棧上分配改為在堆上分配,以確保該變量的生命周期能撐到閉包函數結束。這樣,無論外圍函數何時 return,閉包中捕獲的變量依然有效,直到最后一個引用它的函數也執行完畢,才會被垃圾回收(GC)清理掉。示例代碼如下:

type fetchState struct{mu sync.Mutexfetched map[string]bool
}func ConcurrentMutex(url string,fetcher Fetcher,f *fetchState){f.mu.lock()already :=f.fetched[url]f.fetched[url]=truef.mu.Unlock()if already{return}urls,err := fetcher.Fetcher(url)if err !=nil{return}var wg sync.WaitGroupfor _,u :=range urls{wg.Add(1)//go閉包捕獲引用,每個range重用了ugo func(u string){defer wg.Done()ConcurrentMutex(u,fetcher,f)}(u)}wg.Wait()return
}

? ? ? ? 第二種是通過channel實現協程通信來實現,它遵循 Go 的設計哲學“不要通過共享內存來通信,而應該通過通信來共享內存”的理念。我們無需使用鎖,從而避免了顯式的并發控制復雜性。主線程master 維護抓取狀態,但不共享對象。master中維護了一個map,與基于 mutex 的實現不同,worker 之間并不共享這個 map,而是由 master 單線程統一維護抓取狀態,這樣天然避免了并發沖突。master 與 worker 通過 channel 通信,所有的 URL 抓取任務都通過一個 chan []string 來傳遞,每一個 worker 負責抓取一個頁面并將獲取到的新 URL 列表通過 channel 發送回 master,由 master 決定是否繼續抓取。在master中使用一個變量 n 來記錄當前正在運行的 worker 數量,每創建一個新的 workern++;每處理完一輪從 channel 中讀到的 URL 集合后,n--;n=0 時,說明所有任務已完成,master 主動退出循環。在調用 master之前,ConcurrentChannel會先將種子 URL寫入 channel,我們把這個過程稱為冷啟動機制。在這個過程中,因為 Go 的 channel 默認是無緩沖的,寫入操作是阻塞的,因此這一步必須放在 goroutine 中,防止阻塞主協程。每個 worker 會在一個goroutine中執行,通過 channel 接收 URL,抓取內容,并將抓取到的新 URL 發回 channel。這些worker之間完全獨立,并不共享任何狀態或對象,主從職責清晰。由于Go 的 channel 內部實現中使用了 mutex,因此它天然就是線程安全的,可以安全地在多個 goroutine 之間傳遞數據,而無需加鎖。示例代碼如下:

func worker(url string,ch chan []string,fetcher Fetcher){//實際的抓取邏輯urls,err:=fetcher.Fetch(url)//向channel中發送信息if err!=nil{ch<-[]string{}}else{ch<-urls}
}func master(ch chan []string,fetcher Fetcher){n:=1fetched:=make(map[string]bool)//從channel中獲取一個URLfor urls:=range ch{//再獲取這URL列表中的URLfor_,u:=range urls{//如果這個URL未被抓取,則啟動一個新的worker線程去抓這個URLif fetched[u]==false{fetched[u]=truen+=1go worker(u,ch,fetcher)}}n-=1//爬蟲完成了所有工作,已抓取完每一個URLif n==0{break}}
}func ConcurrentChannel(url string,fetcher Fetcher){ch:=make(chan []string)//將URL種子寫入channelgo func(){ch<-[]string{url}}()master(ch,fetcher)
}

二.服務通信-RPC

(一)既生HTTP,何生RPC?

? ? ? ? 在分布式系統中,各模塊會部署在不同服務器節點上,此時不同節點之間的通信成為開發者必須考慮的問題。在網絡通信實踐中,相信朋友們一定對HTTP這個最常見的web應用層協議再熟悉不過了吧。作為標題黨,可能會有懂行的朋友立刻指出:HTTP和RPC根本就不能這么對比,前者是協議,后者是設計思想。是這樣沒錯,不過在本文中我還非要取這么個標題,沒關系,咱們接著往下看~

? ? ? ? HTTP全稱超文本傳輸協議。常用于萬維網服務器本地瀏覽器之間的數據傳輸,是一個基于TCP的應用層協議。雖然HTTP是web世界的通用協議,但是在追求高性能,低延遲,強類型的分布式系統中,傳統的HTTP+JSON的通信方式已經不能滿足需求了。首先我要說清楚,這里說的HTTP指的是傳統的HTTP/1.1+JSON/REST API模式。雖然也可以用這種方式進行服務調用,不過由于JSON是純文本格式,體積太大,解析慢且占用帶寬;且HTTP/1.1是單請求單連接的形式,無多路復用機制,大量并發請求易造成連接瓶頸和資源浪費,所以不適合服務間的高效通信。而且JSON是弱類型協議,前后端接口如果變動容易出問題,且RESTful API 只是一個風格,沒有強制的規范和工具鏈,文檔靠手寫Swagger,代碼全靠人維護,服務變動時容易出現客戶端和服務端使用兩套接口的問題。HTTP只支持客戶端請求,服務端響應的單向模式,但是在分布式系統中,可能會需要客戶端流服務端流雙向流等多種通信方式。總結來講,HTTP/1.1+JSON/REST API的設計模式只能說對瀏覽器友好,但是不等同于對服務友好。RPC并不是要替代HTTP,而是專為服務間高效通信而設計的一種更專業的方案。

? ? ? ? 其實RPC設計思想的起源,甚至早于HTTP協議,最早可以追溯到上世紀70年代。RPC,即遠程過程調用,其實是一種通信思想,既可以基于TCP,UDP等傳輸層協議,也可以基于HTTP等應用層協議,有很高的可定制性,比如說我們后面要介紹到的gRPC就是以HTTP/2作為底層傳輸協議實現的。RPC并不是協議,但是像Thrift,gRPC這種具體實現才算得上是協議的范疇。在微服務時代,RPC 提供了更強的性能、更高的類型安全、更好的自動化與服務治理能力,是服務間調用的專業工具。

? ? ? ? 我們拿RPC的一種經典實現方式gRPC,在服務通信的場景下,與傳統的HTTP/1.1進行性能對比。首先gRPC支持雙向流服務端流等通信方式,支持多路復用,即在同一個TCP連接上互不干擾地并發處理多個請求,gRPC壓縮請求頭的大小,提高傳輸效率。其次,在序列化層面,gRPC使用的Protobuf(二進制序列化協議)相比純文本的JSON要更加輕量,具有更快的序列化和反序列化的速度,由此節省更多的網絡帶寬,不容忽視的的是Protobuf支持強類型結構,并自動生成多語言代碼,極大提升了開發效率與可靠性。而且,gRPC支持在服務端與客戶端添加攔截器來實現鑒權token校驗限流熔斷追蹤埋點等服務治理的手段,提升了系統的可用性。總結一句話,對人用,選 HTTP/REST,對服務用,選 RPC/gRPC。而實際上,gRPC 與 REST 并不沖突,二者可共存。

(二)gRPC與最佳實踐

????????

? ? ? ? gRPC是由Google公司研發的一款開源的,高性能的遠程過程調用(RPC)框架。實際上,在我的理解來看gRPC既可以理解為框架,也可以理解為協議,所以大可不必為此感到困擾。它使用Protobuf作為序列化格式,同時基于HTTP/2設計,支持多種開發語言。在 gRPC 中,客戶端應用程序可以直接調用另一臺機器上的服務器應用程序的方法,就像調用本地對象一樣。在服務器端,服務器實現此接口并運行 gRPC 服務器來處理客戶端調用。在客戶端,客戶端有一個stub(存根)它提供與服務器相同的方法,gRPC 客戶端和服務器可以在各種環境中運行并相互通信。這里我把gRPC的官方文檔貼出來,朋友們可以參考學習:gRPC官方文檔

????????與許多 RPC 系統一樣,gRPC 基于定義服務的思想,指定可以遠程調用的方法及其參數和返回類型。默認情況下,gRPC 使用Protobuf作為接口定義語言 (IDL),用于描述服務接口和有效消息的結構。這里我節選出我自己項目中某個微服務的一段接口定義和消息結構定義(.proto文件)作為示范:

// 用戶服務接口定義
service UserService {// 用戶注冊:輸入注冊信息,返回注冊結果rpc RegisterUser (RegisterRequest) returns (RegisterResponse);// 用戶登錄:輸入用戶名密碼,返回登錄 tokenrpc LoginUser (LoginRequest) returns (LoginResponse);
}// 消息結構定義 
// 注冊請求
message RegisterRequest {string username = 1;//用戶名string password = 2;//密碼string email = 3;//郵箱string phone = 4;//電話號碼
}// 注冊響應
message RegisterResponse {bool success=1;//是否成功string user_id = 2;//注冊成功后分配的用戶IDstring message = 3;//提示信息
}// 登錄請求
message LoginRequest {string username = 1;//用戶名string password = 2;//密碼
}// 登錄響應(返回JWT)
message LoginResponse {string token = 1;// 返回JWT token,用于鑒權string user_id = 2;//用戶ID
}

? ? ? ? 一旦寫好了.proto文件,gRPC原生提供Protobuf編譯器,我們可以執行相對應的命令,或者編寫腳本,自動生成客戶端和服務端代碼。一般來講客戶端用來調用這些定義好的API,而服務端則實現這些API。這些部分便是一個后端項目真正意義上的業務代碼了,所以我暫時不進行展示。

????????在真正的項目開發過程中,開發者們總結出了一套較為系統的 gRPC 最佳實踐方法。從接口的設計規范、編譯腳本的自動化、到中間件的擴展能力、安全認證、負載均衡再到多語言協同開發,gRPC 已經從最初的高性能通信框架演變為一個現代微服務體系的通信骨干工具。在實際開發過程中,我們往往會引入攔截器提升服務治理能力,使用中間件進行錯誤處理以及重試。我們還經常使用Etcd/Consul等集群管理工具實現服務注冊自動發現,在請求量大時啟用連接池充分復用節省資源等等。無論是構建小型微服務系統,還是支撐復雜的大規模分布式架構,gRPC 都是一個值得考慮的方案。它不只是“比 HTTP 快”,更是更現代、更自動化、更易維護的服務通信解決方案。

? ? ? ? 以上就是我對并發編程和RPC的粗淺理解,如有不當懇請批評指正,我們一起成長!

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

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

相關文章

opensuse/debian grub啟動界面太模糊?

現代操作系統或者新電腦使用那么模糊的界面啟動&#xff0c;雖然沒有什么不良反應&#xff0c;但是多少有點看不過去&#xff0c;這是因為為了保證正常啟動做出的適配。而我們可以對其分辨率進行選定。 1 您好&#xff0c;非常感謝您提供的截圖。這張圖片非常關鍵&#xff0c…

zookeeper Curator(5):集群架構和集群搭建

文章目錄 一、集群架構&#xff1a;Leader-Follower 模式二、核心機制&#xff1a;ZAB 協議三、Leader 選舉機制四、集群部署要點五、優勢與挑戰 Zookeeper 集群是一個由多個 Zookeeper 服務實例組成的分布式協調服務系統&#xff0c; 通過奇數個節點&#xff08;通常 3、5、7…

道可云人工智能每日資訊|浦東啟動人工智能創新應用競賽

道可云人工智能&元宇宙每日簡報&#xff08;2025年7月1日&#xff09;訊&#xff0c;今日人工智能&元宇宙新鮮事有&#xff1a; 江城模境工信部人工智能大模型公共服務平臺&#xff08;武漢&#xff09;上線運行 2025年6月27日&#xff0c;光谷人工智能創新大會在湖北…

Python元組的遍歷

一、前言 在 Python 中&#xff0c;元組&#xff08;tuple&#xff09; 是一種非常基礎且常用的數據結構&#xff0c;它與列表類似&#xff0c;都是有序的序列&#xff0c;但不同的是&#xff0c;元組是不可變的&#xff08;immutable&#xff09;&#xff0c;一旦創建就不能修…

矩陣的條件數(Condition Number of a Matrix)

文章目錄 矩陣的條件數&#xff08;Condition Number of a Matrix&#xff09;&#x1f4cc; 定義&#x1f9ee; 常見形式&#xff1a;2-范數下的條件數&#x1f50d; 條件數的意義&#x1f9e0; 實際意義舉例&#x1f4bb; Python 示例&#xff08;NumPy&#xff09;&#x1f…

1 Studying《Computer Architecture A Quantitative Approach》1-4

目錄 Preface 1 Fundamentals of Quantitative Design and Analysis 1.1 Introduction 1.2 Classes of Computers 1.3 Defining Computer Architecture 1.4 Trends in Technology 1.5 Trends in Power and Energy in Integrated Circuits 1.6 Trends in Cost 1.7 Depe…

Reactor Hot Versus Cold

這段文字詳細解釋了 Reactor 中 熱發布者&#xff08;Hot Publisher&#xff09; 和 冷發布者&#xff08;Cold Publisher&#xff09; 的區別&#xff0c;并通過示例展示了它們的行為差異。以下是對其含義的總結和解釋&#xff1a; 1. 冷發布者&#xff08;Cold Publisher&…

OpenCV CUDA模塊設備層-----逐通道最小值比較函數min()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 OpenCV 的CUDA并行計算模塊&#xff08;cv::cudev&#xff09;中的一個設備端內聯函數&#xff0c;用于在CUDA核函數中對兩個uchar2類型像素值進…

proteus實現stm32按鍵控制LED燈流水燈方向

一、新建工程 1、工程命名 2、選擇工程存儲位置 3、默認下一步 4、默認下一步 5、選擇沒有固件項目&#xff0c;下一步 二、器件放置并連線 1、點擊左邊工具欄中運放的形狀的符號 2、再點擊‘P’&#xff0c;搜索器件 3、搜索器件并放置連線 按鍵控制LED需要的器件有&#…

華為云Flexus+DeepSeek征文 | 讓運維更智能:Chaterm AI終端工具與華為云ModelArts Studio深度集成指南

華為云FlexusDeepSeek征文 | 讓運維更智能&#xff1a;Chaterm AI終端工具與華為云ModelArts Studio深度集成指南 引言一、ModelArts Studio平臺介紹華為云ModelArts Studio簡介ModelArts Studio主要特點 二、Chaterm介紹Chaterm簡介Chaterm主要特點 三、安裝Chaterm工具下載C…

湖北理元理律師事務所債務解法:從法律技術到生活重建

數據透視&#xff1a; 2023年武漢法院受理債務糾紛案11.4萬件&#xff0c;其中37%因不當還款規劃導致債務雪球效應。 一、債務危機的法律歸因 通過分析1200例債務咨詢案例&#xff0c;發現三大共性法律認知盲區&#xff1a; 擔保責任誤判 某企業主為朋友擔保200萬&#xff0…

小程序學習筆記:加載效果、上拉加載與節流處理

在微信小程序開發過程中&#xff0c;優化用戶體驗是非常重要的一環。今天我們就來分享如何在小程序中實現加載提示效果、上拉觸底加載下一頁數據以及對上拉觸底事件進行節流處理&#xff0c;讓你的小程序更加流暢和高效。 一、添加 loading 提示效果 在小程序中&#xff0c;當…

計算機網絡:【socket】【UDP】【地址轉換函數】【TCP】

一.socket 1.1socket接口 它返回的是一個文件描述符。創建socket文件描述符(TCP/UDP,客戶端服務器) ? socket()打開一個網絡通訊端口,如果成功的話,就像 open()一樣返回一個文件描 述符; ? 應用程序可以像讀寫文件一樣用 read/write 在網絡上收發數據; ? 如果 socket()調用…

機器人軌跡跟蹤控制與動力學模型詳解

1. 機器人控制的本質&#xff1a;通過關節扭矩執行軌跡 機器人控制的核心目標是讓機器人關節精確跟蹤期望軌跡 ( q d , q ˙ d , q d ) (q_d, \dot{q}_d, \ddot{q}_d) (qd?,q˙?d?,q?d?)。為此&#xff0c;控制器需根據當前狀態 ( q , q ˙ ) (q, \dot{q}) (q,q˙?)計…

智能辦公與科研革命:ChatGPT+DeepSeek大模型在論文撰寫、數據分析與AI建模中的實踐指南

隨著人工智能技術的快速發展&#xff0c;大語言模型如ChatGPT和DeepSeek在科研領域的應用正在為科研人員提供強大的支持。這些模型通過深度學習和大規模語料庫訓練&#xff0c;能夠幫助科研人員高效地篩選文獻、生成論文內容、進行數據分析和優化機器學習模型。 ChatGPT和Deep…

運營商場景下的實時脫敏方案:PB 級日志流的分布式處理架構

在數字化浪潮中&#xff0c;運營商積累了海量數據&#xff0c;涵蓋用戶信息、通信記錄、業務運營數據等。這些數據不僅是運營商業務運營的關鍵資產&#xff0c;也是創新服務、精準營銷的核心驅動力。然而&#xff0c;隨著數據量呈指數級增長&#xff0c;運營商每日需處理 PB 級…

docker+n8n的工作流中無法使用本地ollama服務的問題

使用docker創建n8n服務后&#xff0c;工作流中不想用大模型付費API測試&#xff0c;想用本地大模型來跑&#xff0c;剛好電腦上裝了ollama&#xff0c;就試了下添加ollama節點來替代大模型付費API&#xff0c;結果就遇到了以下問題 ollama正常運行中 但是工作流會卡在這&…

通過交互式可視化探索波動方程-AI云計算數值分析和代碼驗證

波動方程是一個基本的數學模型&#xff0c;它描述了各種類型的波&#xff08;包括機械波、聲波、電磁波和流體波&#xff09;如何通過不同的介質傳播&#xff0c;這使得它對于物理學、工程學和其他科學學科中聲學、光學、醫學成像和電信等領域的預測和設計都至關重要。 波動方程…

10授權

目錄 本節大綱 一、權限管理 1. 認證 2. 授權 二、授權核心概念 三、權限管理策略 1. 基于 URL 權限管理 權限表達式 2. 基于 方法 權限管理 EnableGlobalMethodSecurity 四、基本用法 五、原理分析 六、實戰 1. 簡介 2. 庫表設計 3. 創建 springboot 應用 本節…

線性規劃模型

線性規劃算是數學建模中最基礎的模型了&#xff0c;其典型特征就是線性和有限資源&#xff0c;即在一組線性約束條件下&#xff0c;求解一個線性目標函數的最大值或最小值問題&#xff1a; 其中x 是決策變量向量&#xff0c;c 是目標函數系數向量&#xff0c;a 和 b 分別是約束…