網站首頁 編程語言 正文
一、怎么才能讓主goroutine等待其它goroutine
方法一:讓主goroutine "sleep"一段時間
func main() { for i := 0; i < 10; i++ { go func(i int) { fmt.Println(i) }(i) } time.Sleep(time.Microsecond * 100) }
缺點是:睡眠的時間很難把握。
方法二:使用通道,使用chan struct{}
類型
func main() { num := 10 var ch = make(chan struct{}, num) for i := 0; i < num; i++ { go func(i int) { fmt.Println(i) ch <- struct{}{} }(i) } for i := 0; i < num; i++ { <-ch } }
類型字面量struct{}
有些類似空接口類型interface{}
,它代表了即不包含任何字段也不擁有任何方法的空結構體類型。
struct{}
類型值的表示法只有一個,即:struct{}{}
。并且它占用的內存空間是0字節,確切地說,這個值在整個GO程序中永遠都只會存在一份。
方法三:使用sync.WaitGroup
待補充。
二、怎么讓多個goroutine按照既定的順序運行
package main import ( "fmt" "sync/atomic" "time" ) func main() { num := uint32(100) var count uint32 = 0 trigger := func(i uint32, fn func()) { for { if atomic.LoadUint32(&count) == i { fn() atomic.AddUint32(&count, 1) break } // 這里加Sleep語句是很有必要的 time.Sleep(time.Microsecond) } } for i := uint32(0); i < num; i++ { go func(i uint32) { fn := func() { fmt.Println(i) } trigger(i, fn) }(i) } trigger(num, func() {}) }
這里的trigger函數實現了一種自旋(spining)。
上面的自旋中添加了time.Sleep(time.Microsecond)
語句:
這主要是因為:Go 調度器在需要的時候只會對正在運行的 goroutine 發出通知,試圖讓它停下來。但是,它卻不會也不能強行讓一個 goroutine 停下來。
所以,如果一條 for 語句過于簡單的話,比如這里的 for 語句就很簡單(因為里面只有一條 if 語句),那么當前的 goroutine 就可能不會去正常響應(或者說沒有機會響應)Go 調度器的停止通知。
因此,這里加一個 sleep 是為了:在任何情況下(如任何版本的 Go、任何計算平臺下的 Go、任何的 CPU 核心數等),內含這條 for 語句的這些 goroutine 都能夠正常地響應停止通知。
不加Sleep語句,可能會導致一直搶占不到資源,也就沒有機會運行,就可能會導致程序一直運行,不會終止。
樂觀鎖:總是假設在“我”操作共享資源的過程中沒有“其他人”競爭操作。如果發現“其他人”確實在此期間競爭了,也就是發現假設失敗,那就等一等再操作。CAS原子操作基本上能夠體現出這種思想。通常,低頻的并發操作適合用樂觀鎖。樂觀鎖一般會用比較輕量級的同步方法(如原子操作),但也不是100%。注意,高頻的操作用樂觀鎖的話反而有可能影響性能,因為多了一步“探查是否有人與我競爭”的操作(當然了,標準的CAS操作可以把這種影響降到最低)。
悲觀鎖:總是假設在“我”操作共享資源的過程中一定有“其他人”競爭操作。所以“我”會先用某種同步方法(如互斥鎖)保護我的操作。這樣的話,“我”在將要操作的時候就沒必要去探查是否有人與我競爭(因為“我”總是假設肯定有競爭,而且已經做好了保護)。通常,頻次較高的并發操作適合用悲觀鎖。不過,如果并發操作的頻次非常低,用悲觀鎖也是可以的,因為這種情況下對性能影響不大。
最后,一定要注意,使用任何同步方法和異步方法都首先要考慮程序的正確性,并且還要考慮程序的性能。程序的正確性一定要靠功能測試來保障,程序的性能一定要靠性能測試來保障。
原文鏈接:https://blog.csdn.net/hefrankeleyn/article/details/128475128
相關推薦
- 2022-11-03 C++構造函數初始化列表的實現詳解_C 語言
- 2022-07-13 w2ui fixedBody 屬性
- 2022-06-12 python操作RabbitMq的三種工作模式_python
- 2022-04-10 Blazor框架簡介_基礎應用
- 2023-05-31 Pandas多個條件(AND,OR,NOT)中提取行_python
- 2023-01-18 一文帶你了解Qt中槽的使用_C 語言
- 2022-05-14 Python實現簡單的圖書管理系統_python
- 2022-09-17 Python高效處理大文件的方法詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支