本文目錄一覽:
- 1、為什麼用golang作為遊戲服務端的開發語言,它的並發性如何
- 2、golang語言map的並發和排序
- 3、【golang】高並發下TCP常見問題解決方案
- 4、如何模擬千萬並發 golang
- 5、Golang 並發讀寫map安全問題詳解
- 6、Go sync/atomic包Load和Store並發不安全
為什麼用golang作為遊戲服務端的開發語言,它的並發性如何
你想想,如果你對怎麼用C語言寫高並發程序一無所知,你上golang就可以自動寫出高並發程序了?其實很多時候幻覺就發生在這裡。
我當初用delphi的時候還是個傻逼,現在用C++已經牛逼了,有時候我就總是會覺得C++寫出來的程序就是比delphi的bug少,雖然這顯然不成立。
golang語言map的並發和排序
golang語言map的並發和排序
golang預設的map不是thread safe的,如果存在讀寫並發的使用場景,必須在外面使用lock機制。
包sync裡面引入一個安全map;
用法:
運行結果如下:
golang官方說法map並不排序,不按key排序,也不按插入順序排序,也就是說map是無序的,無法保證任何排序。
下面是一種常見的給map排序輸出的辦法:
【golang】高並發下TCP常見問題解決方案
首先,看一下TCP握手簡單描繪過程:
其握手過程原理,就不必說了,有很多詳細文章進行敘述,本文只關注研究重點。
在第三次握手過程中,如果伺服器收到ACK,就會與客戶端建立連接,此時內核會把連接從半連接隊列移除,然後創建新的連接,並將其添加到全連接隊列,等待進程調用。
如果伺服器繁忙,來不及調用連接導致全連接隊列溢出,伺服器就會放棄當前握手連接,發送RST給客戶端,即connection reset by peer。
在linux平台上,客戶端在進行高並發TCP連接處理時,最高並發數量都要受系統對用戶單一進程同時打開文件數量的限制(這是因為系統每個TCP都是SOCKET句柄,每個soker句柄都是一個文件),當打開連接超過限制,就會出現too many open files。
使用下指令查看最大句柄數量:
增加句柄解決方案
如何模擬千萬並發 golang
學習了go的基本的並發變成模式,思路就是一個用通信來共享數據,而並不是像java一樣共享內存來通訊。go採用了用channel來傳遞消息,每一個協程持有一個信道,當信道可用時便可以讀寫數據,各信道間的處理數據互不影響。回想一下java中的並發編程,通常我們是因為操作一個數據而採用多線程並發訪問,比較明顯的是更新cache中的key對應的value.
讓我更是歡喜的時在golang中提供了sync.Once這個神器,從此做系統級的開關不再苦惱,天然的保證了就算多個協程並發的情況下也只有一個協程執行once.Do(func()),其他的協程阻塞。你再想想java裡面完成一個系統級初始化,做到並發安全且一次,你要搞一個boolean、再搞把鎖,再寫邏輯,神啊想想頭都大了。
Golang 並發讀寫map安全問題詳解
下面先寫一段測試程序,然後看下運行結果:
運行結果:
發生了錯誤,提示:fatal error: concurrent map read and map write, map 發生了同時讀和寫了; 但是這個錯誤並不是每次運行都會出現,就是有的時候會出現,有的時候並不會出現,根據筆者多次運行結果(其他例子,讀者可以自己嘗試下)來看還會有另外一種報錯就是:fatal error: concurrent map writes,就是map發生了同時寫,但是只是讀是不會有問題的。關於不同的運行結果小夥伴們可以自己寫幾個例子去測試下。下面就這兩個錯誤的發生,筆者給出如下解釋:
(1) fatal error: concurrent map read and map write
就是當一個goroutine在寫數據,而同時另外一個goroutine要讀數據就會報錯,不過這個報錯也很好理解:還沒寫完就讀,讀的數據會有問題,或者反過來還沒讀完就開始寫了,同樣會導致讀取的數據有問題;
(2) fatal error: concurrent map writes
兩個goroutine 同時寫一個內存地址,這種操作也是不允許的,會導致一些比較奇怪的問題;
總體來看其實就是寫map的操作和其他的讀或者寫同時發生了,導致的報錯,做過幾年開發的人可能會想到使用鎖來解決,比如寫map某個key的時候,通過鎖來保證其他goroutine不能再對其寫或者讀了。
實現思路:
(1) 當寫map的某個key時,通過鎖來保證其他goroutine不能再對其寫或者讀了。
(2) 當讀map的某個key時,通過鎖來保證其他的goroutine不能再對其寫,但是可以讀。
於是我們馬上想到golang 的讀寫鎖貌似符合需求,下面來實現下:
再來看下運行結果:
發現沒有報錯了,並且多次運行的結果都不會報錯,說明這個方法是有用的,不過在go1.9版本後就有sync.Map了,不過這個適用場景是讀多寫少的場景,如果寫很多的話效率比較差,具體的原因在這裡筆者就不介紹了,後面會寫篇文章詳細介紹下。
今天的文章就到這裡了,如果有不對的地方歡迎小夥伴給我留言,看到會即時回復的。
Go sync/atomic包Load和Store並發不安全
前言:為了保證並發安全,go語言中可以使用原子操作。其執行過程不能被中斷,這也就保證了同一時刻一個線程的執行不會被其他線程中斷,也保證了多線程下數據操作的一致性。
在atomic包中對幾種基礎類型提供了原子操作,包括int32,int64,uint32,uint64,uintptr,unsafe.Pointer。
對於每一種類型,提供了五類原子操作分別是
Load和Store操作對應與變數的原子性讀寫,許多變數的讀寫無法在一個時鐘周期內完成,而此時執行可能會被調度到其他線程,無法保證並發安全。
⚠️Load 只保證讀取的不是正在寫入的值,Store只保證寫入是原子操作。
所以在使用的時候要注意。
下面簡單示例:
點擊?查看源碼,哈哈哈…
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/280593.html