チャネル(channel)を通して、goroutine間でデータを送受信

Goでは、複数のgoroutine間でデータをやり取りするために、チャネル(channel)という仕組みが用意されています。チャネルを利用することで、goroutine間でデータの送受信を実行できます。

チャネルを通じたデータの送受信
(受信ブロック)

package main

import "fmt"

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

func main() {
	// チャネルの作成
	ch := make(chan int)

	s := []int{1, 1, 1}
	go sum(s, ch)
	
	// チャネルからデータを受信(受信ブロック)
	sum := <-ch
	fmt.Println(sum)
}

sum := <-ch の箇所で処理をブロッキングしているため、sync.WaitGroup を利用して処理を待機する必要はありません。

3

チャネルのバッファ
(送信ブロック)

チャネルにバッファを付けると、受信準備ができていなくても、容量分だけチャネルに送信することができます。

チャネルの容量に空きが無くなると、送信側が処理待ち状態(送信ブロック)になります。

package main

import "fmt"

func main() {
	// 容量2のチャネルを作成
	ch := make(chan string, 2)

	ch <- "aaaa"
	ch <- "bbbb"

	// 容量2なのでエラーになります。(fatal error: all goroutines are asleep - deadlock!)
	// ch <- "cccc"

	// チャネルからデータを受信
	m1 := <-ch
	fmt.Println(m1)

	m2 := <-ch
	fmt.Println(m2)

	// 容量に空きができたので、送信できます。
	ch <- "cccc"
	m3 := <-ch
	fmt.Println(m3)
}
aaaa
bbbb
cccc

送信専用・受信専用チャネル

定義のしかたによって、チャネルを送信専用・受信専用にすることができます。

chanの右側に<-演算子を記述すると送信専用になります。
chanの左側に<-演算子を記述すると受信専用になります。

package main

import (
	"fmt"
	"sync"
)

// ch 送信専用
func test1(ch chan<- string, wg *sync.WaitGroup) {
	defer wg.Done()
	ch <- "aaaa"
}

// ch 受信専用
func test2(ch <-chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	m := <-ch
	fmt.Println(m)
}

func main() {
	var wg sync.WaitGroup
	ch := make(chan string)

	wg.Add(2)
	go test1(ch, &wg)
	go test2(ch, &wg)
	wg.Wait()
}
aaaa

rangeでチャネルがcloseされるまで受信

rangeを利用して、チャネルからデータを受信する例を示します。

close()によってチャネルがクローズされるまで、データを受信し続けます。

package main

import "fmt"

func test(s [][]int, ch chan int) {
	// チャネルを閉じる
	defer close(ch)

	for _, v := range s {
		sum := 0
		for _, v2 := range v {
			sum += v2
		}
		// チャネルに送信
		ch <- sum
	}
}

func main() {
	// チャネルの作成
	ch := make(chan int)

	s := [][]int{
		{1, 1, 1},
		{2, 2, 2},
		{3, 3, 3},
	}
	go test(s, ch)

	// チャネルが閉じられるまで受信
	for i := range ch {
		fmt.Println(i)
	}
}
3
6
9

selectで複数チャネルを同時受信

selectを利用すると、複数チャネルから同時受信できます。

package main

import (
	"fmt"
	"time"
)

func test1(ch chan<- string) {
	for {
		ch <- "test1"
		time.Sleep(2 * time.Second)
	}
}

func test2(ch chan<- string) {
	for {
		ch <- "test2"
		time.Sleep(4 * time.Second)
	}
}

func test3(quit chan<- int) {
	time.Sleep(10 * time.Second)
	quit <- 0
}

func main() {
	c1 := make(chan string)
	c2 := make(chan string)
	quit := make(chan int)
	go test1(c1)
	go test2(c2)
	go test3(quit)

	cnt := 0
	for {
		select {
		case s1 := <-c1:
			fmt.Println(s1)
		case s2 := <-c2:
			fmt.Println(s2)
		case <-quit:
			fmt.Println("quit")
			return
		default:
			cnt = cnt + 1
			fmt.Printf("(cnt: %v)\n", cnt)
			time.Sleep(1 * time.Second)
		}
	}
}
(cnt: 1)
test1
test2
(cnt: 2)
(cnt: 3)
test1
(cnt: 4)
(cnt: 5)
(cnt: 6)
test1
test2
(cnt: 7)
(cnt: 8)
(cnt: 9)
test1
(cnt: 10)
test2
quit

参考

【エンジニア向け】仕事を見つける方法

転職する

転職エージェントを活用する

転職サイトの場合、自身でサイト上から企業を探す必要があります。 一方「レバテックキャリア」 などの転職エージェントの場合、エージェントが企業を紹介してくれます。エージェントが間に入ることにより、日程調整や、条件交渉などもサポートしてくれます。

転職ドラフトを活用する

転職ドラフト」は、 企業がITエンジニアをドラフトという形で指名するサービスです。年収が最初に提示されるなどのメリットがあります。 ただ、初回登録時にレジュメ作成が必要で、すでにエンジニア経験が豊富にあるエンジニア向けのサービスかと思います。 レジュメ作成が手間ですが、自身のキャリアを見直す機会になり、他の仕事探しにも役立つはずです。

エンジニア転職保証のあるスクールを活用する

ある程度、開発経験のあるかたであれば、独学で必要なスキルを身につけることができるはずです。ただ、別業種からエンジニアに転職したい場合など、1から独学で学ぶのはハードルが高いです。そういった方は、スクールの活用を検討しても良いと思います。 「TechAcademy」は、エンジニア転職保証コースを提供しています。給付金制度の対象講座として認定されているため、金銭面の負担も抑えることができます。

フリーランスとして活動する

レバテックフリーランス」「ITプロパートナーズ」「ギークスジョブ」は、フリーランスエージェントサービスです。 エージェントによって、支払いサイトなど細かい違いはありますが、まずは良い案件を見つけることが重要です。 登録自体は無料なので、複数エージェントに登録して、より多くの案件を紹介してもらうのがおすすめです。

logo
わくわくBank.
技術系の記事を中心に、役に立つと思ったこと、整理したい情報などを掲載しています。