9
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Golang】Go言語 channel(チャネル)について

Posted at

##channelとは?

Goroutineは並行実行されているので、通常だとデータのやりとりができません。
しかし、channelというのををつかうとデータのやりとりができます。

トンネルをつなぐようなイメージです!


package main

import (
	"fmt"
)

func goroutine1(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
    //チャネルにデータを送信
	c <- sum
}

func main() {
	s := []int{1, 2, 3, 4}
	c := make(chan int)
	go goroutine1(s, c)
      //送られてきたデータを受信
	p := <-c
	fmt.Println(p) // => 10
}

c <- sum でcに値を送信し、p := <-c で受信しています。ここでは受信するまでブロッキングされていて、pはsumを受信するまで待っている状態です。sync.Waitと同じような状態ですね!

##Buffered channels
バッファとはプログラムで処理を行なうときに、データを一時的に格納するためのメモリー領域のことをいいます。
チャネルに一時データを保存するイメージです。


package main

import "fmt"

func main() {
	//2つまでバッファを保存できる
	ch := make(chan int, 2)
	ch <- 100
	//len()でチャネルの長さを調べられる
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	//3つめのデータを送信しようとするとエラーになる
	ch <- 300
	fmt.Println(len(ch)) // => fatal error: all goroutines are asleep - deadlock!
}
実行結果
1
2
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
	/tmp/sandbox795806942/prog.go:11 +0x16f

2つまでしか保存できないので、3つめを送信しようとすると当然ですがエラーになります。(デッドロック)

↓にように手前で一個チャネルを取りだしてから300を送信すれば、エラーにならなくなります。


func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))

	x := <-ch
	fmt.Println(x)
	ch <- 300
	fmt.Println(len(ch))
}
実行結果
1
2
100
2

次に以下のコードをご覧ください↓


package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))

	for c := range ch {
		fmt.Println(c)
	}
}

これはチャネルをrangeでループさせようとしているのですが、これはエラーになります。

実行結果
1
2
100
200
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
	/tmp/sandbox892357489/prog.go:12 +0x1f3

これは存在しない3つ目のチャネルまでループしようとしてしまうからです。
2つ目のチャネルでループ処理を止めるにはチャネルを一旦クローズする必要があります。
そのためにはclose(ch)を記述する必要があります。


package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 100
	fmt.Println(len(ch))
	ch <- 200
	fmt.Println(len(ch))
	close(ch)
	for c := range ch {
		fmt.Println(c)
	}
}
実行結果
1
2
100
200

##最後まで読んでいただきありがとうございます!
ご指摘などございましたら、コメントいただけると幸いです!!

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?