<del id="d4fwx"><form id="d4fwx"></form></del>
      <del id="d4fwx"><form id="d4fwx"></form></del><del id="d4fwx"><form id="d4fwx"></form></del>

            <code id="d4fwx"><abbr id="d4fwx"></abbr></code>
          • golang中g(shù)oroutine的使用方法-創(chuàng)新互聯(lián)

            這篇文章將為大家詳細(xì)講解有關(guān)golang中g(shù)oroutine的使用方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

            成都創(chuàng)新互聯(lián)公司專注于企業(yè)網(wǎng)絡(luò)營銷推廣、網(wǎng)站重做改版、渭濱網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為渭濱等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

            go中的goroutine是go語言在語言級別支持并發(fā)的一種特性。初接觸go的時候?qū)o的goroutine的歡喜至極,實現(xiàn)并發(fā)簡便到簡直bt的地步。

            但是在項目過程中,越來越發(fā)現(xiàn)goroutine是一個很容易被大家濫用的東西。goroutine是一把雙面刃。這里列舉一下goroutine使用的幾宗罪:

            1、goroutine的指針傳遞是不安全的

            fun main() {
                request := request.NewRequest() //這里的NewRequest()是傳遞回一個type Request的指針
                go saveRequestToRedis1(request)
                go saveReuqestToRedis2(request)
                 
                select{}
             
            }

            非常符合邏輯的代碼:

            主routine開一個routine把request傳遞給saveRequestToRedis1,讓它把請求儲存到redis節(jié)點1中

            同時開另一個routine把request傳遞給saveReuqestToRedis2,讓它把請求儲存到redis節(jié)點2中

            然后主routine就進(jìn)入循環(huán)(不結(jié)束進(jìn)程)

            問題現(xiàn)在來了,saveRequestToRedis1和saveReuqestToRedis2兩個函數(shù)其實不是我寫的,而是團(tuán)隊另一個人寫的,我對其中的實現(xiàn)一無所知,也不想去仔細(xì)看內(nèi)部的具體實現(xiàn)。但是根據(jù)函數(shù)名,我想當(dāng)然地把request指針傳遞進(jìn)入。

            實際上saveRequestToRedis1和saveRequestToRedis2 是這樣實現(xiàn)的:

            func saveRequestToRedis1(request *Request){
                 …
                 request.ToUsers = []int{1,2,3} //這里是一個賦值操作,修改了request指向的數(shù)據(jù)結(jié)構(gòu)
                 …
                redis.Save(request)
                return
            }

            這樣有什么問題?saveRequestToRedis1和saveReuqestToRedis2兩個goroutine修改了同一個共享數(shù)據(jù)結(jié)構(gòu),但是由于routine的執(zhí)行是無序的,因此我們無法保證request.ToUsers設(shè)置和redis.Save()是一個原子操作,這樣就會出現(xiàn)實際存儲redis的數(shù)據(jù)錯誤的bug。

            好吧,你可以說這個saveRequestToRedis的函數(shù)實現(xiàn)的有問題,沒有考慮到會是使用go routine調(diào)用。請再想一想,這個saveRequestToRedis的具體實現(xiàn)是沒有任何問題的,它不應(yīng)該考慮上層是怎么使用它的。

            那就是我的goroutine的使用有問題,主routine在開一個routine的時候并沒有確認(rèn)這個routine里面的任何一句代碼有沒有修改了主routine中的數(shù)據(jù)。對的,主routine確實需要考慮這個情況。

            主goroutine在啟用go routine的時候需要閱讀子routine中的每行代碼來確定是否有修改共享數(shù)據(jù)??這在實際項目開發(fā)過程中是多么降低開發(fā)速度的一件事情??!

            go語言使用goroutine是想減輕并發(fā)的開發(fā)壓力,卻不曾想是在另一方面增加了開發(fā)壓力。

            上面說的那么多,就是想得出一個結(jié)論:

            gorotine的指針傳遞是不安全的??!

            如果上一個例子還不夠隱蔽,這里還有一個例子:

            fun (this *Request)SaveRedis() {
                redis1 := redis.NewRedisAddr("xxxxxx")
                redis2 := redis.NewRedisAddr("xxxxxx")
                go this.saveRequestToRedis(redis1)
                go this.saveRequestToRedis(redis2)
                 
                select{}
            }

            很少人會考慮到this指針指向的對象是否會有問題,這里的this指針傳遞給routine應(yīng)該說是非常隱蔽的。

            2、goroutine增加了函數(shù)的危險系數(shù)

            這點其實也是源自于上面一點。上文說,往一個go函數(shù)中傳遞指針是不安全的。那么換個角度想,你怎么能保證你要調(diào)用的函數(shù)在函數(shù)實現(xiàn)內(nèi)部不會使用go呢?如果不去看函數(shù)體內(nèi)部具體實現(xiàn),是沒有辦法確定的。

            例如我們將上面的典型例子稍微改改

            func main() {
                request := request.NewRequest()
                saveRequestToRedis1(request)
                saveRequestToRedis2(request)
                select{}
            }

            這下我們沒有使用并發(fā),就一定不會出現(xiàn)這問題了吧?追到函數(shù)里面去,傻眼了:

            func saveReqeustToRedis1(request *Request) {
                       …
                        go func() {
                      …
                      request.ToUsers = []{1,2,3}
                     ….
                     redis.Save(request)
                }
            }

            里面起了一個goroutine,并修改了request指針指向的對象。這里就產(chǎn)生了錯誤了。好吧,如果在調(diào)用函數(shù)的時候,不看函數(shù)內(nèi)部的具體實現(xiàn),這個問題就無法避免。

            所以說,從最壞的思考角度出發(fā),每個調(diào)用函數(shù)理論上來說都是不安全的!試想一下,這個調(diào)用函數(shù)如果不是自己開發(fā)組的人編寫的,而是使用網(wǎng)絡(luò)上的第三方開源代碼...確實無法想象找出這個bug要花費多少時間。

            3、goroutine的濫用陷阱

            看一下這個例子:

            func main() {
                go saveRequestToRedises(request)
            }
             
            func saveRequestToRedieses(request *Request) {
                for _, redis := range Redises {
                    go redis.saveRequestToRedis(request)
                }
            }
             
            func saveRequestToRedis(request *Request) {
                        ….
                        go func() {
                                 request.ToUsers = []{1,2,3}
                                    …
                                    redis.Save(request)
                        }
             
            }

            神奇啊,go無處不在,好像眨眨眼就在哪里冒出來了。這就是go的濫用,到處都見到go,但是卻不是很明確,哪里該用go?為什么用go?goroutine確實會有效率的提升么?

            c語言的并發(fā)比go語言的并發(fā)復(fù)雜和繁瑣地多,因此我們在使用之前會深思,考慮使用并發(fā)獲得的好處和壞處。

            處理方法

            下面說幾個我處理這些問題的方法:

            1、當(dāng)啟動一個goroutine的時候,如果一個函數(shù)必須要傳遞一個指針,但是函數(shù)層級很深,在無法保證安全的情況下,傳遞這個指針指向?qū)ο蟮囊粋€克隆,而不是直接傳遞指針

            fun main() {
                request := request.NewRequest()
                go saveRequestToRedis1(request.Clone())
                go saveReuqestToRedis2(request.Clone())
                 
                select{}
             
            }

            Clone函數(shù)需要另外寫。可以在結(jié)構(gòu)體定義之后簡單跟上這個方法。比如:

            func (this *Request)Clone(){
                newRequest := NewRequst()
                newRequest.ToUsers = make([]int, len(this.ToUsers))
                copy(newRequest.ToUsers, this.ToUsers)
             
            }

            其實從效率角度考慮這樣確實會產(chǎn)生不必要的Clone的操作,耗費一定內(nèi)存和CPU。但是在我看來,首先,為了安全性,這個嘗試是值得的。

            其次,如果項目對效率確實有很高的要求,那么你不妨在開發(fā)階段遵照這個原則使用clone,然后在項目優(yōu)化階段,作為一種優(yōu)化手段,將不必要的Clone操作去掉。這樣就能在保證安全的前提下做到最好的優(yōu)化。

            2、什么時候使用go的問題

            有兩種思維邏輯會想到使用goroutine:

            1 業(yè)務(wù)邏輯需要并發(fā)

            比如一個服務(wù)器,接收請求,阻塞式的方法是一個請求處理完成后,才開始第二個請求的處理。其實在設(shè)計的時候我們一定不會這么做,我們會在一開始就已經(jīng)想到使用并發(fā)來處理這個場景,每個請求啟動一個goroutine為它服務(wù),這樣就達(dá)到了并行的效果。這種goroutine直接按照思維的邏輯來使用goroutine

            2 性能優(yōu)化需要并發(fā)

            一個場景是這樣:需要給一批用戶發(fā)送消息,正常邏輯會使用

            for _, user := range users {
                sendMessage(user)
             
            }

            但是在考慮到性能問題的時候,我們就不會這樣做,如果users的個數(shù)很大,比如有1000萬個用戶?我們就沒必要將1000萬個用戶放在一個routine中運(yùn)行處理,考慮將1000萬用戶分成1000份,每份開一個goroutine,一個goroutine分發(fā)1萬個用戶,這樣在效率上會提升很多。這種是性能優(yōu)化上對goroutine的需求

            按照項目開發(fā)的流程角度來看。在項目開發(fā)階段,第一種思路的代碼實現(xiàn)會直接影響到后續(xù)的開發(fā)實現(xiàn),因此在項目開發(fā)階段應(yīng)該馬上實現(xiàn)。

            但是第二種,項目中是由很多小角落是可以使用goroutine進(jìn)行優(yōu)化的,但是如果在開發(fā)階段對每個優(yōu)化策略都考慮到,那一定會直接打亂你的開發(fā)思路,會讓你的開發(fā)周期延長,而且很容易埋下潛在的不安全代碼。

            因此第二種情況在開發(fā)階段絕不應(yīng)該直接使用goroutine,而該在項目優(yōu)化階段以優(yōu)化的思路對項目進(jìn)行重構(gòu)。

            關(guān)于golang中g(shù)oroutine的使用方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

            另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

            當(dāng)前標(biāo)題:golang中g(shù)oroutine的使用方法-創(chuàng)新互聯(lián)
            網(wǎng)站URL:http://www.jbt999.com/article44/ccdehe.html

            成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)網(wǎng)站策劃、營銷型網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站、面包屑導(dǎo)航、外貿(mào)網(wǎng)站建設(shè)

            廣告

            聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

            成都定制網(wǎng)站建設(shè)

              <del id="d4fwx"><form id="d4fwx"></form></del>
              <del id="d4fwx"><form id="d4fwx"></form></del><del id="d4fwx"><form id="d4fwx"></form></del>

                    <code id="d4fwx"><abbr id="d4fwx"></abbr></code>
                  • 91麻豆精品成人一区二区 | 久久久成人高清视频 | 俺也来最新色视频 | 淫色综合网站 | 天天射天天日天天干天天操 |