日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Go 包循環引用及對策,你學會了嗎?

來源: 責編: 時間:2024-03-18 09:37:21 172觀看
導讀引言從 Java 轉到 Go 的開發同學,大概都會踩到第一個“坑”:Go 的包循環引用。Go 的包循環引用是什么意思呢?有一定經驗的開發者都知道循環依賴,比如 A 依賴了 B, B 依賴了 C ,C 又依賴了 A。這就構成了一個循環依賴(有環圖)

引言

從 Java 轉到 Go 的開發同學,大概都會踩到第一個“坑”:Go 的包循環引用。Tq728資訊網——每日最新資訊28at.com

Go 的包循環引用是什么意思呢?有一定經驗的開發者都知道循環依賴,比如 A 依賴了 B, B 依賴了 C ,C 又依賴了 A。這就構成了一個循環依賴(有環圖)。Tq728資訊網——每日最新資訊28at.com

在 Java 里面,循環依賴是類級別的;但 Go 里要更嚴格一些:Go 的循環引用判定是 包級別的。舉個例子,包 A 下的類 A 依賴了包 B 下的類 B,類 B 又依賴了包 C 下的類 C, 類 C 又依賴了包 A 下的 D。在 Java 里面,這里并沒有構成循環依賴。但在 Go 里面,這導致了包循環引用:包 A => 包 B = > 包 C => 包 A。Go 會編譯不通過:報 import circle not allowed。Tq728資訊網——每日最新資訊28at.com

對包依賴不太重視的人,初期會感到不適應。本文舉幾個自己踩過的坑,作一說明。Tq728資訊網——每日最新資訊28at.com

包循環引用釋例

對象導致的包循環引用

哎呀呀,初來乍到,一下子給我來了八個包循環引用,打擊得我有點不知所措了。這是怎么回事呢 ?Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

第一個循環引用,是因為上報的包 agent 下對象 DetectionBase 依賴了包 denoise 下的降噪模型結果對象 HitDenoiseModel,而在某一處,HitDenoiseModel  又引用了包 agent 下的另一個對象。Tq728資訊網——每日最新資訊28at.com

為什么會發生這個事情?這是因為,圖省事,我直接把輸出對象放到了輸入對象的包里,不想復制一份。正確的做法是,輸入的對象只能放輸入對象,不能放輸出對象,否則依賴就會擴大出去。Tq728資訊網——每日最新資訊28at.com

如何解決?有兩種方案:Tq728資訊網——每日最新資訊28at.com

  • 把 HitDenoiseModel 放在 agent 包下。然后定義另一個對象 denoise/DenoiseResultModel,將 FillHitDenoiseModel 方法移到包 denoise 下,HitDenoiseModel 賦值給 DenoiseResultModel。這樣形成了包 denoise => agent 的單向依賴,保證“輸出 =>輸入” 的單向依賴。不過,這種方法還是存在“篡改”原始數據的小罪行。
  • 不對 DetectionBase 做任何變更,新創建一個包和對象,把 HitDenoiseModel 放在新創建對象里,同時將 FillHitDenoiseModel 方法移到新創建對象的包下。3

啟示:避免篡改輸入對象。應用中的對象往往是很多的,不太重視包依賴,很容易造成對象的循環引用。即使你自己能夠小心確保不出問題,也會和別人添加的類造成循環引用。Tq728資訊網——每日最新資訊28at.com

發送消息與接收消息循環引用

梅開二度。又來了一個包循環引用。Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

這又是怎么回事?有了第一次經驗,第二次就不那么慌了。先提個 MR ,看看引入了哪些類。尤其是循環引用的那條鏈路。我們看到 cdc/msg 這個地方作為起點開始循環。為什么會有循環呢?因為我本來打算把 msg 相關的消息對象和消息處理都放在一起。但這種方式很容易導致 循環引用。為什么呢?因為 引入消息對象的時候, 就會把包下的所有類引入的所有包都引進來,這樣就會把 /cdc/msg/XXXReceiver 引入,進而引入 /cdc/handler/XXXhandler, 而 msg/handler/XXXhandler 又會引入 msg/XXXSender。就導致了包循環引用依賴。Tq728資訊網——每日最新資訊28at.com

看來之前還是隨意慣了。Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

怎么解決?把 XXXReceiver 放在包 receiver 下,把 XXXSender 放在包 sender 下即可。Tq728資訊網——每日最新資訊28at.com

啟示:Tq728資訊網——每日最新資訊28at.com

  • 引入類的包要小,這樣就很類似 Java 的全限定性包,減少循環引用的可能性。
  • 簡單的消息對象與復雜的消息處理不要放在一起,因為引入簡單的就會把復雜的引入,復雜的又會遞歸引入更多的依賴。

internal 引用了 share

一鍵三連。Tq728資訊網——每日最新資訊28at.com

下圖又是怎么回事?借鑒業界最佳實踐,咱們把一個工程下的代碼分為了 internal 和 share。其中 internal 的代碼不能被其它模塊訪問,只有 share 下的代碼作為橋梁,為其它模塊提供服務。Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

這個是因為 internal/detect_config/AService 引用了 share/detect_config/BService ,然后 share/detect_config/CService 又引用了 internal/detect_config/DService。internal 包怎么能夠引用 share 下的包呢 ?內部模塊怎么能夠依賴外部模塊 ?世界似乎不那么美好了。Tq728資訊網——每日最新資訊28at.com

與同事討論,他們認為,helper 不應該依賴 service ,而應該依賴 repository, 而我一直認為 helper 是對 service 提供服務的一種高層封裝, helper 依賴 service 是很正常。helper 依賴 repository, 看上去說得也很有道理。不過 internal 模塊依賴 share 模塊,看上去總是感覺有點違反單向依賴的設計原則。Tq728資訊網——每日最新資訊28at.com

經過討論后,我和同事各做了修改。我的修改是讓 helper 依賴 repository, 同事的修改是,把原來 service 拆分成公共的 service 和內部的 service,保證 share 對 internal 的單向依賴。Tq728資訊網——每日最新資訊28at.com

運行時循環依賴

即使你幸運地逃過了包循環引用的檢測,但存在運行時循環依賴,Go 會直接卡住。Tq728資訊網——每日最新資訊28at.com

一個例子如下圖所示:有若干個流程組件 A, B, C,加載到一個工廠 F 下,由一個 執行器 E 依次從 F 中取出執行。但是呢,在流程組件C 中,又依賴了 E 來執行任務。這樣會導致循環依賴。在 Java 中,Spring 會忽略組件 C, 初始化成功,但運行時找不到 C 而導致流程出錯(可以用懶加載機制解決);但是 Go 就不那么幸運了(也許是幸運的,因為它讓你早點發現問題)。Tq728資訊網——每日最新資訊28at.com

對于這種場景,可以用消息隊列來解耦。Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

對策匯總

遇到包循環引用,有哪些經驗可循呢 ?Tq728資訊網——每日最新資訊28at.com

(1) 提倡小而獨立的包。不要把大量的有關聯的類都放在一個包下。這樣,很容易因為一個類的引入,而引入更多依賴,導致依賴不可控。Tq728資訊網——每日最新資訊28at.com

(2)單向依賴原則。internal 下的類不應當依賴 share 下的類。因為 share 下的類一定會依賴 internal。如果 internal 又依賴 share ,就破壞了“單向依賴”原則。當工程越來越大時,一定會有一個點會爆發。不是不報,時候未到。細分包可以緩解這種問題,但不能從根本上避免單向依賴的破壞。Tq728資訊網——每日最新資訊28at.com

(3) 依賴倒置原則。盡量依賴接口,而不是具體實現類。Tq728資訊網——每日最新資訊28at.com

(4)使用消息隊列解耦依賴。Tq728資訊網——每日最新資訊28at.com

(5)相對合理的依賴方向:model => (constants, 無依賴的 model) ; dto => types => constants ;util => (dto, types, constants, models);service =>  repository => model ;helper => (repository, util, cache) ; controller => (helper, service) ;  receiver => handler => (service, helper)Tq728資訊網——每日最新資訊28at.com

最后問一句:Go 為什么不允許包循環引用呢 ?聽聽 Go 語言作者怎么說:Tq728資訊網——每日最新資訊28at.com

圖片圖片Tq728資訊網——每日最新資訊28at.com

再聽聽 AI 怎么說 :Tq728資訊網——每日最新資訊28at.com

圖片Tq728資訊網——每日最新資訊28at.com

小結

本文討論了幾個包循環引用的例子,并給出了相應的對策。Tq728資訊網——每日最新資訊28at.com

個人覺得,這種禁止循環引用的做法還是可取的,能培養良好的設計習慣。軟件開發,本質是應對結構復雜性的技藝。而設計思維,則是應對結構復雜性的重要法寶。開發人員應多多學習設計思考,保持系統和架構的優雅。Tq728資訊網——每日最新資訊28at.com

參考資料

  • go循環依賴最佳解決方案[1]

Reference

[1]go循環依賴最佳解決方案:https://juejin.cn/post/7290389972406501432Tq728資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-76488-0.htmlGo 包循環引用及對策,你學會了嗎?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: JQuery 4.0震撼發布:這是復興還是告別?

下一篇: 業務開發做到零 bug 有多難?

標簽:
  • 熱門焦點
  • 影音體驗是真的強 簡單聊聊iQOO Pad

    大公司的好處就是產品線豐富,非常細分化的東西也能給你做出來,例如早先我們看到了新的vivo Pad2,之后我們又在iQOO Neo8 Pro的發布會上看到了iQOO的首款平板產品iQOO Pad。雖
  • 7月安卓手機性價比榜:努比亞+紅魔兩款新機入榜

    7月登場的新機有努比亞Z50S Pro和紅魔8S Pro,除了三星之外目前唯二的兩款搭載超頻版驍龍8Gen2處理器的產品,而且努比亞和紅魔也一貫有著不錯的性價比,所以在本次的性價比榜單
  • 從 Pulsar Client 的原理到它的監控面板

    背景前段時間業務團隊偶爾會碰到一些 Pulsar 使用的問題,比如消息阻塞不消費了、生產者消息發送緩慢等各種問題。雖然我們有個監控頁面可以根據 topic 維度查看他的發送狀態,
  • 如何通過Python線程池實現異步編程?

    線程池的概念和基本原理線程池是一種并發處理機制,它可以在程序啟動時創建一組線程,并將它們置于等待任務的狀態。當任務到達時,線程池中的某個線程會被喚醒并執行任務,執行完任
  • 三分鐘白話RocketMQ系列—— 如何發送消息

    我們知道RocketMQ主要分為消息 生產、存儲(消息堆積)、消費 三大塊領域。那接下來,我們白話一下,RocketMQ是如何發送消息的,揭秘消息生產全過程。注意,如果白話中不小心提到相關代
  • “又被陳思誠騙了”

    作者|張思齊 出品|眾面(ID:ZhongMian_ZM)如今的國產懸疑電影,成了陳思誠的天下。最近大爆電影《消失的她》票房突破30億斷層奪魁暑期檔,陳思誠再度風頭無兩。你可以說陳思誠的
  • iQOO Neo8系列新品發布會

    旗艦雙芯 更強更Pro
  • 榮耀Magicbook V 14 2021曙光藍版本正式開售,擁有觸摸屏

    榮耀 Magicbook V 14 2021 曙光藍版本正式開售,搭載 i7-11390H 處理器與 MX450 顯卡,配備 16GB 內存與 512GB SSD,重 1.48kg,厚 14.5mm,具有 1.5mm 鍵盤鍵程、
  • 微軟發布Windows 11新版 引入全新任務欄狀態

    近日,微軟發布了Windows 11新版,而Build 22563更新主要引入了幾周前曝光的平板模式任務欄等,系統更流暢了。更新中,Windows 11加入了專門針對平板優化的任務欄
Top 主站蜘蛛池模板: 治县。| 弥勒县| 辰溪县| 台北县| 东丽区| 龙游县| 涡阳县| 襄垣县| 滁州市| 天津市| 沛县| 南靖县| 巴中市| 慈溪市| 宁波市| 米林县| 通化市| 理塘县| 秦皇岛市| 建宁县| 黎川县| 水城县| 永济市| 屯门区| 云南省| 合川市| 澄江县| 增城市| 长寿区| 宁德市| 滦平县| 南和县| 仁怀市| 会同县| 晋城| 县级市| 南召县| 泰顺县| 阳东县| 平山县| 抚顺县|