欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談golang for 循環(huán)中使用協(xié)程的問題

 更新時間:2020年12月21日 14:17:53   作者:胖達團長  
這篇文章主要介紹了淺談golang for 循環(huán)中使用協(xié)程的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

兩個例子

package main 
import (
 "fmt"
 "time"
)
 
func Process1(tasks []string) {
 for _, task := range tasks {
 // 啟動協(xié)程并發(fā)處理任務(wù)
 go func() {
 fmt.Printf("Worker start process task: %s\n", task)
 }()
 }
}
 
func main() { 
 tasks := []string{"1", "2", "3", "4", "5"}
 Process1(tasks)
 time.Sleep(2 * time.Second)
}

結(jié)果:

第一次運行

Worker start process task: 3
Worker start process task: 4
Worker start process task: 4
Worker start process task: 5
Worker start process task: 5

第二次運行

Worker start process task: 2
Worker start process task: 5
Worker start process task: 5
Worker start process task: 5
Worker start process task: 5
package main 
import (
 "fmt"
 "time"
)
 
func Process1(tasks []string) {
 for _, task := range tasks {
 // 啟動協(xié)程并發(fā)處理任務(wù)
 go func() {
 fmt.Printf("Worker start process task: %s\n", task)
 }()
 }
}
 
func Process2(tasks []string) {
 for _, task := range tasks {
 // 啟動協(xié)程并發(fā)處理任務(wù)
 go func(t string) {
 fmt.Printf("Worker start process task: %s\n", t)
 }(task)
 }
}
func main() {
 tasks := []string{"1", "2", "3", "4", "5"}
 Process2(tasks)
 time.Sleep(2 * time.Second)
}

結(jié)果

第一次運行

Worker start process task: 5
Worker start process task: 4
Worker start process task: 2
Worker start process task: 3
Worker start process task: 1

第二次運行

Worker start process task: 2
Worker start process task: 5
Worker start process task: 4
Worker start process task: 1
Worker start process task: 3

上述問題,有個共同點就是都引用了循環(huán)變量。即在for index, value := range xxx語句中,

index和value便是循環(huán)變量。不同點是循環(huán)變量的使用方式,有的是直接在協(xié)程中引用(題目一),有的作為參數(shù)傳遞(題目二)。

循環(huán)變量是易變的

首先,循環(huán)變量實際上只是一個普通的變量。

語句for index, value := range xxx中,每次循環(huán)index和value都會被重新賦值(并非生成新的變量)。

如果循環(huán)體中會啟動協(xié)程(并且協(xié)程會使用循環(huán)變量),就需要格外注意了,因為很可能循環(huán)結(jié)束后協(xié)程才開始執(zhí)行,

此時,所有協(xié)程使用的循環(huán)變量有可能已被改寫。(是否會改寫取決于引用循環(huán)變量的方式)

循環(huán)變量需要綁定

在題目一中,協(xié)程函數(shù)體中引用了循環(huán)變量task,協(xié)程從被創(chuàng)建到被調(diào)度執(zhí)行期間循環(huán)變量極有可能被改寫,所以會出現(xiàn)兩次結(jié)果相差較大,比如第一個協(xié)程啟動for range變量正好循環(huán)到3,for屬于主協(xié)程的一部分。go func是子協(xié)程,主子分開看。這種情況下,其實for range里面的循環(huán)變量沒有跟子協(xié)程綁定,稱之為變量沒有綁定。所以,題目一打印結(jié)果是混亂的。很有可能(隨機)所有協(xié)程執(zhí)行的task都是列表中的最后一個task,也可能不是。

在題目二中,協(xié)程函數(shù)體中并沒有直接引用循環(huán)變量task,而是使用的參數(shù)與協(xié)程進行了綁定。而在創(chuàng)建協(xié)程時,循環(huán)變量task

作為函數(shù)參數(shù)傳遞給了協(xié)程。參數(shù)傳遞的過程實際上也生成了新的變量,也即間接完成了綁定。

所以,題目二實際上是沒有問題的。就是實際參數(shù)順序是按照for range產(chǎn)生的變量順序綁定給子協(xié)程的。

ps:

簡單點來說

如果循環(huán)體沒有并發(fā)出現(xiàn),則引用循環(huán)變量一般不會出現(xiàn)問題;

如果循環(huán)體有并發(fā),則根據(jù)引用循環(huán)變量的位置不同而有所區(qū)別

通過參數(shù)完成綁定,則一般沒有問題;

函數(shù)體中引用,則需要顯式地綁定

補充:Go語言的協(xié)程中,寫死循環(huán)的注意點:

現(xiàn)象:

在寫Go的多協(xié)程程序時,出現(xiàn)過幾次無法理解的情況。

有一次,我想寫一個能跑滿cpu的程序,最容易想到的就是,開幾個Go的協(xié)程,每個協(xié)程里寫死循環(huán)。沒想到,運行的時候發(fā)現(xiàn),協(xié)程就只開出了一個。

另一次,我寫了個程序,也是開了多個協(xié)程。因為如果不阻塞住主函數(shù),主函數(shù)一結(jié)束,程序就會結(jié)束。所以我就在主函數(shù)結(jié)束前加了個死循環(huán)。然后就發(fā)現(xiàn)整個協(xié)程都被卡住了。

分析:

其實,這個東西是協(xié)程的特點。以前沒用過協(xié)程,加上Go又說可以當(dāng)線程用。所以想當(dāng)然的寫了死循環(huán)。

準確的說,是在Go語言里,寫了死循環(huán),并且死循環(huán)內(nèi)并沒有什么系統(tǒng)調(diào)用,只有簡單的計算這類的。你就會發(fā)現(xiàn),Go的協(xié)程調(diào)度就廢掉了。

協(xié)程并非像線程那樣,是由CPU中斷來觸發(fā)切換的。它不是應(yīng)用程序能控制的(操作系統(tǒng)內(nèi)核的某些關(guān)鍵操作會被保護,不被中斷)。即使你在線程里寫了死循環(huán),只要周期一到,CPU產(chǎn)生終端,死循環(huán)會被打斷,重新調(diào)度。但是,協(xié)程就不是這樣了,協(xié)程的調(diào)度其實是在協(xié)程調(diào)用了某個系統(tǒng)調(diào)用時,自動跳到另一個協(xié)程執(zhí)行。也就是這個“中斷”是程序主動產(chǎn)生的,而不是被”中斷”。

所以,協(xié)程中,如果你寫了死循環(huán),那你的死循環(huán)就會一直跑著,而不會讓別的協(xié)程運行。主函數(shù)中也是一樣,而且主函數(shù)中執(zhí)行這個會讓整個協(xié)程卡住,因為調(diào)度的代碼沒法被執(zhí)行。

在Go語言中,如果你想寫死循環(huán),循環(huán)里面沒有系統(tǒng)調(diào)用,又想讓Go的協(xié)程能起作用,只需要在死循環(huán)里面加一條語句即可。估計系統(tǒng)調(diào)用時也是這個語句起的作用。

runtime.Gosched() //主動讓出時間片

還可以使用

select{}

來實現(xiàn)無限阻塞,而不是使用for{}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Golang中切片的用法與本質(zhì)詳解

    Golang中切片的用法與本質(zhì)詳解

    Go的切片類型為處理同類型數(shù)據(jù)序列提供一個方便而高效的方式,下面這篇文章就來給大家介紹了關(guān)于Golang中切片的用法與本質(zhì)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-07-07
  • 教你利用Golang可選參數(shù)實現(xiàn)可選模式

    教你利用Golang可選參數(shù)實現(xiàn)可選模式

    本文討論Golang函數(shù)可選參數(shù)及函數(shù)類型,以及如何利用可選函數(shù)類型實現(xiàn)可選模式。同時通過構(gòu)造函數(shù)作為示例,實現(xiàn)強大帶可選參數(shù)的構(gòu)造函數(shù),讓代碼更直觀、靈活、支持擴展
    2023-01-01
  • Go語言包管理模式示例分析

    Go語言包管理模式示例分析

    這篇文章主要為大家介紹了Go語言包管理模式示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 如何使用Go語言獲取當(dāng)天、昨天、明天、某天0點時間戳以及格式化時間

    如何使用Go語言獲取當(dāng)天、昨天、明天、某天0點時間戳以及格式化時間

    這篇文章主要給大家介紹了關(guān)于如何使用Go語言獲取當(dāng)天、昨天、明天、某天0點時間戳以及格式化時間的相關(guān)資料,格式化時間戳是將時間戳轉(zhuǎn)換為特定的日期和時間格式,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • Go語言map字典用法實例分析

    Go語言map字典用法實例分析

    這篇文章主要介紹了Go語言map字典用法,實例分析了map字典的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Go語言獲取文件的名稱、前綴、后綴

    Go語言獲取文件的名稱、前綴、后綴

    這篇文章主要介紹了Go語言獲取文件的名稱、前綴、后綴,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang實現(xiàn)文件夾的創(chuàng)建與刪除的方法詳解

    Golang實現(xiàn)文件夾的創(chuàng)建與刪除的方法詳解

    這篇文章主要介紹了如何利用Go語言實現(xiàn)對文件夾的常用操作:創(chuàng)建于刪除。文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05
  • Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實例探究

    Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實例探究

    當(dāng)涉及到訂單處理系統(tǒng)時,觀察者設(shè)計模式可以用于實現(xiàn)訂單狀態(tài)的變化和通知,在這篇文章中,我們將介紹如何使用Golang來實現(xiàn)觀察者設(shè)計模式,并提供一個基于訂單處理系統(tǒng)的代碼示例
    2024-01-01
  • Go標準庫strconv實現(xiàn)string類型與其他基本數(shù)據(jù)類型之間轉(zhuǎn)換

    Go標準庫strconv實現(xiàn)string類型與其他基本數(shù)據(jù)類型之間轉(zhuǎn)換

    這篇文章主要為大家介紹了Go標準庫strconv實現(xiàn)string類型與其他基本數(shù)據(jù)類型之間轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Go語言中的switch用法實例分析

    Go語言中的switch用法實例分析

    這篇文章主要介紹了Go語言中的switch用法,實例分析了switch的功能及使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02

最新評論