<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                Golang中常用的并發模型有三種: * 通過channel通知實現并發控制 無緩沖的通道指的是通道的大小為0,也就是說,這種類型的通道在接收前沒有能力保存任何值,它要求發送 goroutine 和接收 goroutine 同時準備好,才可以完成發送和接收操作。 從上面無緩沖的通道定義來看,發送 goroutine 和接收 gouroutine 必須是同步的,同時準備后,如果沒有同時準備好的話,先執行的操作就會阻塞等待,直到另一個相對應的操作準備好為止。這種無緩沖的通道我們也稱之為同步通道。 ~~~go func main() { ch := make(chan struct{}) go func() { fmt.Println("start working") time.Sleep(time.Second * 1) ch <- struct{}{} }() <-ch fmt.Println("finished") } ~~~ 當主 goroutine 運行到`<-ch`接受 channel 的值的時候,如果該 channel 中沒有數據,就會一直阻塞等待,直到有值。 這樣就可以簡單實現并發控制 * 通過sync包中的WaitGroup實現并發控制 Goroutine是異步執行的,有的時候為了防止在結束main函數的時候結束掉Goroutine,所以需要同步等待,這個時候就需要用 WaitGroup了,在Sync包中,提供了 WaitGroup,它會等待它收集的所有 goroutine 任務全部完成。 在WaitGroup里主要有三個方法: * Add, 可以添加或減少 goroutine的數量. * Done, 相當于Add(-1). * Wait, 執行后會堵塞主線程,直到WaitGroup 里的值減至0. 在主goroutine 中 Add(delta int) 索要等待goroutine 的數量。在每一個goroutine 完成后Done()表示這一個goroutine 已經完成,當所有的 goroutine 都完成后,在主 goroutine 中 WaitGroup 返回。 ~~~go func main(){ var wg sync.WaitGroup var urls = []string{ "http://www.golang.org/", "http://www.google.com/", } for _, url := range urls { wg.Add(1) go func(url string) { defer wg.Done() http.Get(url) }(url) } wg.Wait() } ~~~ 在Golang官網中對于WaitGroup介紹是`A WaitGroup must not be copied after first use`,在 WaitGroup 第一次使用后,不能被拷貝。 應用示例: ~~~go func main(){ wg := sync.WaitGroup{} for i := 0; i < 5; i++ { wg.Add(1) go func(wg sync.WaitGroup, i int) { fmt.Printf("i:%d", i) wg.Done() }(wg, i) } wg.Wait() fmt.Println("exit") } ~~~ 運行: ~~~go i:1i:3i:2i:0i:4fatal error: all goroutines are asleep - deadlock! goroutine 1 [semacquire]: sync.runtime_Semacquire(0xc000094018) /home/keke/soft/go/src/runtime/sema.go:56 +0x39 sync.(*WaitGroup).Wait(0xc000094010) /home/keke/soft/go/src/sync/waitgroup.go:130 +0x64 main.main() /home/keke/go/Test/wait.go:17 +0xab exit status 2 ~~~ 它提示所有的`goroutine`都已經睡眠了,出現了死鎖。這是因為 wg 給拷貝傳遞到了 goroutine 中,導致只有 Add 操作,其實 Done操作是在 wg 的副本執行的。 因此 Wait 就會死鎖。 這個第一個修改方式: 將匿名函數中 wg 的傳入類型改為`*sync.WaitGroup`,這樣就能引用到正確的`WaitGroup`了。 這個第二個修改方式: 將匿名函數中的 wg 的傳入參數去掉,因為Go支持閉包類型,在匿名函數中可以直接使用外面的 wg 變量. * 在Go 1.7以后引進的強大的Context上下文,實現并發控制. 通常,在一些簡單場景下使用 channel 和 WaitGroup 已經足夠了,但是當面臨一些復雜多變的網絡并發場景下`channel`和`WaitGroup`顯得有些力不從心了。 比如一個網絡請求 Request,每個 Request 都需要開啟一個 goroutine 做一些事情,這些 goroutine 又可能會開啟其他的 goroutine,比如數據庫和RPC服務。 所以我們需要一種可以跟蹤 goroutine 的方案,才可以達到控制他們的目的,這就是Go語言為我們提供的 Context,稱之為上下文非常貼切,它就是goroutine 的上下文。 它是包括一個程序的運行環境、現場和快照等。每個程序要運行時,都需要知道當前程序的運行狀態,通常Go 將這些封裝在一個 Context 里,再將它傳給要執行的 goroutine 。 context 包主要是用來處理多個 goroutine 之間共享數據,及多個 goroutine 的管理。 context 包的核心是 struct Context,接口聲明如下: ~~~go // A Context carries a deadline, cancelation signal, and request-scoped values // across API boundaries. Its methods are safe for simultaneous use by multiple // goroutines. type Context interface { // Done returns a channel that is closed when this `Context` is canceled // or times out. // Done() 返回一個只能接受數據的channel類型,當該context關閉或者超時時間到了的時候,該channel就會有一個取消信號 Done() <-chan struct{} // Err indicates why this Context was canceled, after the Done channel // is closed. // Err() 在Done() 之后,返回context 取消的原因。 Err() error // Deadline returns the time when this Context will be canceled, if any. // Deadline() 設置該context cancel的時間點 Deadline() (deadline time.Time, ok bool) // Value returns the value associated with key or nil if none. // Value() 方法允許 Context 對象攜帶request作用域的數據,該數據必須是線程安全的。 Value(key interface{}) interface{} } ~~~ Context 對象是線程安全的,你可以把一個 Context 對象傳遞給任意個數的 gorotuine,對它執行取消操作時,所有 goroutine 都會接收到取消信號。 一個 Context 不能擁有 Cancel 方法,同時我們也只能 Done channel 接收數據。其中的原因是一致的:接收取消信號的函數和發送信號的函數通常不是一個。 典型的場景是:父操作為子操作操作啟動 goroutine,子操作也就不能取消父操作。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看