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

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

聽我一句勸,業務代碼中,別用多線程。

來源: 責編: 時間:2023-11-06 08:52:41 233觀看
導讀你好呀,我是歪歪。前幾天我在網上沖浪,看到一個哥們在吐槽,說他工作三年多了,沒使用過多線程。雖然八股文背的滾瓜爛熟,但是沒有在實際開發過程中寫的都是業務代碼,沒有使用過線程池,心里還是慌得一比。我只是微微一笑,這不是

你好呀,我是歪歪。mZh28資訊網——每日最新資訊28at.com

前幾天我在網上沖浪,看到一個哥們在吐槽,說他工作三年多了,沒使用過多線程。mZh28資訊網——每日最新資訊28at.com

雖然八股文背的滾瓜爛熟,但是沒有在實際開發過程中寫的都是業務代碼,沒有使用過線程池,心里還是慌得一比。mZh28資訊網——每日最新資訊28at.com

我只是微微一笑,這不是很正常嗎?mZh28資訊網——每日最新資訊28at.com

業務代碼中一般也使不上多線程,或者說,業務代碼中不知不覺你以及在使用線程池了,你再 duang 的一下搞一個出來,反而容易出事。mZh28資訊網——每日最新資訊28at.com

所以提到線程池的時候,我個人的觀點是必須把它吃得透透的,但是在業務代碼中少用或者不用多線程。mZh28資訊網——每日最新資訊28at.com

關于這個觀點,我給你盤一下。mZh28資訊網——每日最新資訊28at.com

Demo

首先我們還是花五分鐘搭個 Demo 出來。mZh28資訊網——每日最新資訊28at.com

我手邊剛好有一個之前搭的一個關于 Dubbo 的 Demo,消費者、生產者都有,我就直接拿來用了:mZh28資訊網——每日最新資訊28at.com

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

這個 Demo 我也是跟著網上的 quick start 搞的:https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/spring-boot/mZh28資訊網——每日最新資訊28at.com

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

可以說寫的非常詳細了,你就跟著官網的步驟一步步的搞就行了。mZh28資訊網——每日最新資訊28at.com

我這個 Demo 稍微不一樣的是我在消費者模塊里面搞了一個 Http 接口:mZh28資訊網——每日最新資訊28at.com

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

在接口里面發起了 RPC 調用,模擬從前端頁面發起請求的場景,更加符合我們的開發習慣。mZh28資訊網——每日最新資訊28at.com

而官方的示例中,是基于了 SpringBoot 的 CommandLineRunner 去發起調用:mZh28資訊網——每日最新資訊28at.com

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

只是發起調用的方式不一樣而已,其他沒啥大區別。mZh28資訊網——每日最新資訊28at.com

需要說明的是,我只是手邊剛好有一個 Dubbo 的 Demo,隨手就拿來用了,但是本文想要表達的觀點,和你使不使用 Dubbo 作為 RPC 框架,沒有什么關系,道理是通用的。mZh28資訊網——每日最新資訊28at.com

上面這個 Demo 啟動起來之后,通過 Http 接口發起一次調用,看到控制臺服務提供方和服務消費方都有對應的日志輸出,準備工作就算是齊活兒了:mZh28資訊網——每日最新資訊28at.com

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

上菜

在上面的 Demo 中,這是消費者的代碼:mZh28資訊網——每日最新資訊28at.com

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

這是提供者的代碼:mZh28資訊網——每日最新資訊28at.com

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

整個調用鏈路非常的清晰:mZh28資訊網——每日最新資訊28at.com

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

來,請你告訴我這里面有線程池嗎?mZh28資訊網——每日最新資訊28at.com

沒有!mZh28資訊網——每日最新資訊28at.com

是的,在日常的開發中,我就是寫個接口給別人調用嘛,在我的接口里面并沒有線程池相關的代碼,只有 CRUD 相關的業務代碼。mZh28資訊網——每日最新資訊28at.com

同時,在日常的開發中,我也經常調用別人提供給我的接口,也是一把梭,擼到底,根本就不會用到線程池。mZh28資訊網——每日最新資訊28at.com

所以,站在我,一個開發人員的角度,這個里面沒有線程池。mZh28資訊網——每日最新資訊28at.com

合理,非常合理。mZh28資訊網——每日最新資訊28at.com

但是,當我們換個角度,再看看,它也是可以有的。mZh28資訊網——每日最新資訊28at.com

比如這樣:mZh28資訊網——每日最新資訊28at.com

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

反應過來沒有?mZh28資訊網——每日最新資訊28at.com

我們發起一個 Http 調用,是由一個 web 容器來處理這個請求的,你甭管它是 Tomcat,還是 Jetty、Netty、Undertow 這些玩意,反正是個 web 容器在處理。mZh28資訊網——每日最新資訊28at.com

那你說,這個里面有線程池嗎?mZh28資訊網——每日最新資訊28at.com

在方法入口處打個斷點,這個 http-nio-8081-exec-1 不就是 Tomcat 容器線程池里面的一個線程嗎:mZh28資訊網——每日最新資訊28at.com

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

通過 dump 堆棧信息,過濾關鍵字可以看到這樣的線程,在服務啟動起來,啥也沒干的情況下,一共有 10 個:mZh28資訊網——每日最新資訊28at.com

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

朋友,這不就是線程池嗎?mZh28資訊網——每日最新資訊28at.com

雖然不是你寫的,但是你確實用了。mZh28資訊網——每日最新資訊28at.com

我寫出來的這個 test 接口,就是會由 web 容器中的一個線程來進行調用。所以,站在 web 容器的角度,這里是有一個線程池的:mZh28資訊網——每日最新資訊28at.com

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

同理,在 RPC 框架中,不管是消費方,還是服務提供方,也都存在著線程池。mZh28資訊網——每日最新資訊28at.com

比如 Dubbo 的線程池,你可以看一下官方的文檔:mZh28資訊網——每日最新資訊28at.com

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/mZh28資訊網——每日最新資訊28at.com

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

而對于大多數的框架來說,它絕不可能只有一個線程池,為了做資源隔離,它會啟用好幾個線程池,達到線程池隔離,互不干擾的效果。mZh28資訊網——每日最新資訊28at.com

比如參與 Dubbo 一次調用的其實不僅一個線程池,至少還有 IO 線程池和業務線程池,它們各司其職:mZh28資訊網——每日最新資訊28at.com

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

我們主要關注這個業務線程池。mZh28資訊網——每日最新資訊28at.com

反正站在 Dubbo 框架的角度,又可以補充一下這個圖片了:mZh28資訊網——每日最新資訊28at.com

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

那么問題來了,在當前的這個情況下?mZh28資訊網——每日最新資訊28at.com

當有人反饋:哎呀,這個服務吞吐量怎么上不去啊?mZh28資訊網——每日最新資訊28at.com

你怎么辦?mZh28資訊網——每日最新資訊28at.com

你會 duang 的一下在業務邏輯里面加一個線程池嗎?mZh28資訊網——每日最新資訊28at.com

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

大哥,前面有個 web 容器的線程池,后面有個框架的線程池,兩頭不調整,你在中間加個線程池,加它有啥用啊?mZh28資訊網——每日最新資訊28at.com

web 容器,拿 Tomcat 來說,人家給你提供了線程池參數調整的相關配置,這么一大坨配置,你得用起來啊:mZh28資訊網——每日最新資訊28at.com

https://tomcat.apache.org/tomcat-9.0-doc/config/executor.htmlmZh28資訊網——每日最新資訊28at.com

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

再比如 Dubbo 框架,都給你明說了,這些參數屬于性能調優的范疇,感覺不對勁了,你先動手調調啊:mZh28資訊網——每日最新資訊28at.com

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

你把這些參數調優弄好了,絕對比你直接懟個線程池在業務代碼中,效果好的多。mZh28資訊網——每日最新資訊28at.com

甚至,你在業務代碼中加入一個線程池之后,反而會被“反噬”。mZh28資訊網——每日最新資訊28at.com

比如,你 duang 的一下懟個線程池在這里,我們先只看 web 容器和業務代碼對應的部分:mZh28資訊網——每日最新資訊28at.com

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

由于你的業務代碼中有線程池的存在,所以當接受到一個 web 請求之后,立馬就把請求轉發到了業務線程池中,由線程池中的線程來處理本次請求,從而釋放了 web 請求對應的線程,該線程又可以里面去處理其他請求。mZh28資訊網——每日最新資訊28at.com

這樣來看,你的吞吐量確實上去了。mZh28資訊網——每日最新資訊28at.com

在前端來看,非常的 nice,請求立馬得到了響應。mZh28資訊網——每日最新資訊28at.com

但是,你考慮過下游嗎?mZh28資訊網——每日最新資訊28at.com

你的吞吐量上漲了,下游同一時間處理的請求就變多了。如果下游跟不上處理,頂不住了,直接就是崩給你看怎么辦?mZh28資訊網——每日最新資訊28at.com

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

而且下游不只是你一個調用方,由于你調用的太猛,導致其他調用方的請求響應不過來,是會引起連鎖反應的。mZh28資訊網——每日最新資訊28at.com

所以,這種場景下,為了異步懟個線程池放著,我覺得還不如用消息隊列來實現異步化,頂天了也就是消息堆積嘛,總比服務崩了好,這樣更加穩妥。mZh28資訊網——每日最新資訊28at.com

或者至少和下游勾兌一下,問問我們這邊吞吐量上升,你們扛得住不。mZh28資訊網——每日最新資訊28at.com

有的小伙伴看到這里可能就會產生一個疑問了:歪師傅,你這個講得怎么和我背的八股文不一樣啊?mZh28資訊網——每日最新資訊28at.com

巧了,你背過的八股文我也背過,現在我們來溫習一下我們背過的八股文。mZh28資訊網——每日最新資訊28at.com

什么時候使用線程池呢?mZh28資訊網——每日最新資訊28at.com

比如一個請求要經過若干個服務獲取數據,且這些數據沒有先后依賴,最終需要把這些數據組合起來,一并返回,這樣經典的場景:mZh28資訊網——每日最新資訊28at.com

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

用戶點商品詳情,你要等半天才展示給用戶,那用戶肯定罵罵咧咧的久走了。mZh28資訊網——每日最新資訊28at.com

這個時候,八股文上是怎么說的:用線程池來把串行的動作改成并行。mZh28資訊網——每日最新資訊28at.com

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

這個場景也是增加了服務 A 的吞吐量,但是用線程池就是非常正確的,沒有任何毛病。mZh28資訊網——每日最新資訊28at.com

但是你想想,我們最開始的這個案例,是這個場景嗎?mZh28資訊網——每日最新資訊28at.com

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

我們最開始的案例是想要在業務邏輯中增加一個線程池,對著一個下游服務就是一頓猛攻,不是所謂的串行改并行,而是用更多的線程,帶來更多的串行。mZh28資訊網——每日最新資訊28at.com

這已經不是一個概念了。mZh28資訊網——每日最新資訊28at.com

還有一種場景下,使用線程池也是合理的。mZh28資訊網——每日最新資訊28at.com

比如你有一個定時任務,要從數據庫中撈出狀態為初始化的數據,然后去調用另外一個服務的接口查詢數據的最終狀態。mZh28資訊網——每日最新資訊28at.com

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

如果你的業務代碼是這樣的:mZh28資訊網——每日最新資訊28at.com

//獲取訂單狀態為初始化的數據(0:初始化 1:處理中 2:成功 3:失敗)//select * from order where order_status=0;ArrayList initOrderInfoList = queryInitOrderInfoList();//循環處理這批數據for(OrderInfo orderInfo : initOrderInfoList){    //捕獲異常以免一條數據錯誤導致循環結束    try{        //發起rpc調用        String orderStatus = queryOrderStatus(orderInfo.getOrderId);        //更新訂單狀態        updateOrderInfo(orderInfo.getOrderId,orderStatus);      } catch (Exception e){        //打印異常    }}

雖然你框架中使用了線程池,但是你就是在一個 for 循環中不停的去調用下游服務查詢數據狀態,是一條數據一條數據的進行處理,所以其實同一時間,只是使用了框架的線程池中的一個線程。mZh28資訊網——每日最新資訊28at.com

為了更加快速的處理完這批數據,這個時候,你就可以懟一個線程池放在 for 循環里面了:mZh28資訊網——每日最新資訊28at.com

//循環處理這批數據for(OrderInfo orderInfo : initOrderInfoList){    //使用線程池    executor.execute(() -> {        //捕獲異常以免一條數據錯誤導致循環結束        try {            //發起rpc調用            String orderStatus = queryOrderStatus(orderInfo.getOrderId);            //更新訂單狀態            updateOrderInfo(orderInfo.getOrderId, orderStatus);        } catch (Exception e) {            //打印異常        }    });}

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

需要注意的是,這個線程池的參數怎么去合理的設置,是需要考慮的事情。mZh28資訊網——每日最新資訊28at.com

同時這個線程池的定位,就類似于 web 容器線程池的定位。mZh28資訊網——每日最新資訊28at.com

或者這樣對比起來看更加清晰一點:mZh28資訊網——每日最新資訊28at.com

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

定時任務觸發的時候,在發起遠程接口調用之前,沒有線程池,所以我們可以啟用一個線程池來加快數據的處理。mZh28資訊網——每日最新資訊28at.com

而 Http 調用或者 RPC 調用,框架中本來就已經有一個線程池了,而且也給你提供了對應的性能調優參數配置,那么首先考慮的應該是把這個線程池充分利用起來。mZh28資訊網——每日最新資訊28at.com

如果僅僅是因為異步化之后可以提升服務響應速度,沒有達到串行改并行的效果,那么我更加建議使用消息隊列。mZh28資訊網——每日最新資訊28at.com

好了,本文的技術部分就到這里啦。mZh28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-17156-0.html聽我一句勸,業務代碼中,別用多線程。

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

上一篇: 高性能Python開發:解密FastAPI的高并發秘籍!

下一篇: 聊聊Spring 微服務和多租戶

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 大安市| 神农架林区| 陆河县| 阳西县| 钟祥市| 泽普县| 太原市| 贺州市| 浦县| 疏勒县| 简阳市| 赞皇县| 即墨市| 泾源县| 太白县| 陈巴尔虎旗| 卢龙县| 桐乡市| 咸阳市| 和顺县| 汝州市| 沐川县| 余庆县| 涟水县| 永定县| 万安县| 桃江县| 京山县| 禹城市| 石狮市| 平舆县| 夏津县| 浮山县| 丰原市| 新晃| 东乡县| 新沂市| 静海县| 浠水县| 历史| 沁阳市|