Goベース-channelチャネル
2993 ワード
CSP
チャンネルを理解するにはまずCSPモデルを知っておく必要があります.CSPはCommunicating Sequential Processの略称で、中国語は通信順序プロセスと呼ぶことができ、トニー・ホアが1977年に提案した同時プログラミングモデルである.簡単に言えば、CSPモデルは同時実行されるエンティティ(スレッドまたはプロセス)からなり、エンティティ間でメッセージを送信することによって通信され、ここでメッセージを送信する際にチャネル、またはchannelと呼ばれる.CSPモデルの鍵は、メッセージを送信するエンティティではなくchannelに注目することです.Go言語はCSPの一部理論を実現し,goroutineはCSPで同時実行されるエンティティに対応し,channelもCSPのchannelに対応する.
channel
channelは、Go言語が言語レベルで提供するgoroutine間の通信方式である.channelを使用して、2つ以上のgoroutine間でメッセージを伝えることができます.チャネル変数を宣言するときは、チャネルタイプの伝達の要素タイプを決定し、channelを介してオブジェクトを伝達するプロセスと関数を呼び出すときのパラメータ伝達タイプが一致する必要があります.channelの宣言形式は次のとおりです.
var chan
一般的な変数宣言とは異なり、タイプの前にchanキーを付けるだけで、channelを初期化するのも簡単で、内蔵関数make()を直接使用すればいいです.
make(chan Type) // make(chan Type, 0)
make(chan Type, capacity)
make関数は2つのパラメータを受け入れることができます.1番目のパラメータは、初期化される値のタイプを表す字面量(chan intなど)であり、2番目のパラメータはチャネルの容量であり、オプションのパラメータである.たとえば、長さ3で要素タイプintのチャネル値を初期化するには、次のように書く必要がある.
make(chan int, 3)
正確には、チャネル値の長さをキャッシュのサイズと呼ぶべきである.すなわち、チャネル値に一時保存可能なデータの数を表す.したがって、チャネル容量は負数ではなく、チャネル値に早く入れられる(または送信される)ほど、チャネル値に先に取り出される(または受信される)channelの使用法において、1つのチャネルは、先進的な先行(FIFO)キューに類似している.
chanデータ送信と受信
chanデータの送信と受信は、左カッコとマイナス記号の組み合わせ(**送信データがchannelに送信(書き込み)されると、通常、他のgoroutineがこのchannelからデータを読み出すまでプログラムがブロックされます.次のプログラムでデッドロックが発生します.
func foo(in chan int) {
fmt.Println(
データの読み込み
value :=
したがって、チャネル受信および送信の両方のデータはブロックされており、データがチャネルに送信されると、プログラム制御は、他のGoプロトコルがチャネルからデータに読み出されるまで、データを送信する文でブロックされ、ブロックが解除されることに特に注意されたい.これと同様に、チャネルのデータを読み出す場合、他のコヒーレンスがこのチャネルにデータを書き込むことがなければ、読み出しプロセスは常にブロックされる.
import "fmt"
func main() {
c := make(chan int)
go func(){
defer fmt.Println(" ")
fmt.Println(" ")
c
for range遍歴チャネル
for rangeループは、1つのチャネルが閉じる前に、チャネルからデータを受信するために使用される.
func producer(chnl chan int) {
for i := 0; i < 10; i++ {
chnl
ブロッキング特性
Channelの読み取りと書き込みは,それぞれのコモン内部でブロックされている.つまり、パイプがいっぱいになると、あるroutineがchannelからデータを取り出すまで、channelにデータを入れる操作がブロックされ、このデータを入れる操作が実行されます.逆に同じように、パイプが空の場合、あるroutineがこのchannelにデータを入れるまで、channelからデータを取り出す操作がブロックされ、このデータを取り出す操作が実行されます.
func main() {
ch := make(chan int, 3)
ch
メインroutineはchannelにデータを入れますが、channelにはバッファがなく、channelがずっといっぱいになっていることに相当しますので、ここでブロックが発生します.メインroutineがここでブロックすると、デッドロックになります!
func main() {
ch := make(chan int)
ここから、バッファリングされていないchannelでは、挿入操作と取り出し操作が同じroutineではなく、あるroutineが取り出し操作を実行していることを確認してから、別のroutineで挿入操作を実行する必要があることがわかります.
select
タイムアウトせいぎょ
time.Afterメソッドは、次のタイプを返します.
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
go func() {
time.Sleep(2 * time.Second)
c