Golang開発:複数のオプションを選択します

selectはGolangの制御構造であり、文法的にはswitchステートメントと似ていますが、selectはゴルーチン間の通信に使用される点が異なります。各ケースは、送信または受信のいずれかの通信操作である必要があります。Selectは実行可能なランダムケースを実行します。実行するケースがない場合、実行するケースがあるまでゴルーチンはブロックされます。

複数選択を選択

selectの表現は、golangのselectが通信制御ステートメントであることを除いて、基本的にswitchcaseの表現と同じです。selectの実行には、通信の送信または受信が必要です。そうでない場合、通信はブロックされます。

	ch := make(chan bool, 0)
	ch1 := make(chan bool, 0)
	select {
		case ret := <-ch:
			fmt.Println(ret)
		case ret := <-ch1:
			fmt.Println(ret)
	}

chとch1に送信する通信データがない場合、selectはchまたはch1に送信するデータがあるまでブロックし、selectは対応するケースを実行してデータを受け入れます。

selectはタイムアウト制御を実装します

selectメカニズムを使用して、単純なタイムアウト制御を実装できます。
プログラムが完全に実行するコードを最初に見てください

func service(ch chan bool) {
    
    
	time.Sleep(time.Second*3)
	ch<-true
}
func main() {
    
    
	ch := make(chan bool, 0)
	go service(ch)
	select {
    
    
		case ret := <-ch:
			fmt.Println(ret)
		case <-time.After(time.Second*5):
			fmt.Println("timeout")
	}
}

___go_build_main_go #gosetup
true

5Sはtime.Afterタイムアウトを使用して定義され、サービスプログラムは3Sを実行するため、タイムアウトがあってはなりません。これは予想と一致しています。
タイムアウトの実行をもう一度見てみましょう。サービスプログラムの実行時間を6Sに設定します。タイムアウト制御は引き続き5Sであり、実行効果を確認します。

func service(ch chan bool) {
    
    
	time.Sleep(time.Second*6)
	ch<-true
}
func main() {
    
    
	ch := make(chan bool, 0)
	go service(ch)
	select {
    
    
		case ret := <-ch:
			fmt.Println(ret)
		case <-time.After(time.Second*5):
			fmt.Println("timeout")
	}
}

___go_build_main_go #gosetup
timeout

タイムアウトケースの実行は、実際には予想と同じです。

チャネルが閉じているかどうかを判断するために選択します

最初にデータを受信する文法を見てください

val,ok <- ch
ok true 正常接收数据
ok false 通道关闭

実際には、データを受信するための2つのパラメーターがあることがわかります。2番目のブール値は、チャネルが閉じているかどうか、およびデータを正常に受信できるかどうかを反映します。

テストコードを見てください。
データ送信者と2つのデータ受信者を作成しました。送信者がチャネルを閉じると、2つの受信者のゴルーチンは、上記の構文によってチャネルが閉じられているかどうかを判断し、ゴルーチンが終了しているかどうかを判断できます。 。

func sender(ch chan int, wg *sync.WaitGroup) {
    
    
	for i:=0;i<10;i++ {
    
    
		ch<-i
	}
	close(ch)
	wg.Done()
}
func receiver(ch chan int, wg *sync.WaitGroup) {
    
    
	for {
    
    
		if val,ok := <-ch;ok {
    
    
			fmt.Println(fmt.Sprintf("%d,%s",val, "revevier"))
		} else {
    
    
			fmt.Println("quit recevier")
			break;
		}
	}
	wg.Done()
}
func receiver2(ch chan int, wg *sync.WaitGroup) {
    
    
	for {
    
    
		if val,ok := <-ch;ok {
    
    
			fmt.Println(fmt.Sprintf("%d,%s",val, "revevier2"))
		} else {
    
    
			fmt.Println("quit recevier2")
			break;
		}
	}
	wg.Done()
}
func main() {
    
    
	ch := make(chan int, 0)
	wg := &sync.WaitGroup{
    
    }
	wg.Add(1)
	go sender(ch, wg)
	wg.Add(1)
	go receiver(ch, wg)
	wg.Add(1)
	go receiver2(ch, wg)
	wg.Wait()
}

の結果

0,revevier2
2,revevier2
3,revevier2
4,revevier2
5,revevier2
6,revevier2
7,revevier2
1,revevier
9,revevier
quit recevier
8,revevier2
quit recevier2

1つのデータ送信者と2つのデータ受信者が表示されます。チャネルが閉じられると、両方のデータ受信者がチャネルが閉じられたという通知を受信します。
閉じたチャネルにデータを送信すると、プログラムはパニックになります。閉じたチャネルからデータを受信すると、参照の意味がないチャネルタイプのゼロ値データを受信します。Intは0、文字列は空です。 ....。

終了タイマーと他のプログラムを選択します

回転タイマーは開発時によく使用されますが、プログラムが終了すると回転タイマーを閉じることができません。実際、selectはこの問題を解決できます。
ローテーションタスクがある場合は、タイマーが必要で、3Sごとにロジックを実行し、10S後にこのタイマーを閉じます。

コードを見てください

func TimeTick(wg *sync.WaitGroup,q chan bool) {
    
    
	defer wg.Done()
	t := time.NewTicker(time.Second*3)
	defer t.Stop()
	for {
    
    
		select {
    
    
		case <-q:
			fmt.Println("quit")
			return
		case <-t.C:
			fmt.Println("seconds timer")
		}
	}
}
func main() {
    
    
	q := make(chan bool)
	wg := new(sync.WaitGroup)
	wg.Add(1)
	go TimeTick(wg,q)
	time.Sleep(time.Second*10)
	close(q)
	wg.Wait()
}

の結果

seconds timer
seconds timer
seconds timer
quit

チャネルを閉じて、ポーリングタイマーのゴルーチンを正常に終了します。

おすすめ

転載: blog.csdn.net/feifeixiang2835/article/details/108723186