goroutine
Go言語では、ゴルーチン(goroutine)と呼ばれる軽量なスレッドを使用して、並行処理を実現することができます。ゴルーチンはGoランタイムによってスケジュールされ、マルチコアのCPUやスレッドプールに対して効率的にマッピングされます。
ゴルーチンを使うことで、非同期な処理や並行処理を直感的かつ簡単に実現できます。ゴルーチンは、goキーワードを使って関数の呼び出し前に開始されます。ゴルーチン内での処理は非同期に実行され、ゴルーチン間でのデータの共有には明示的な同期が必要です。
以下に、ゴルーチンの例を示します。
package main
import (
"fmt"
"time"
)
func main() {
// ゴルーチン内で非同期に関数を実行
go sayHello()
// メインゴルーチンからの処理
for i := 0; i < 5; i++ {
fmt.Println("メインゴルーチン:", i)
time.Sleep(time.Millisecond * 500)
}
}
func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("ゴルーチン:", i)
time.Sleep(time.Millisecond * 500)
}
}
この例では、sayHelloという関数をゴルーチンとして実行しています。goキーワードを使ってsayHello()と呼び出すことで、sayHello関数がゴルーチンとして非同期に実行されます。
メインゴルーチンはforループを通じて自身の処理を実行し、同時にゴルーチンの処理も行われます。メインゴルーチンとゴルーチンは並行して実行されるため、出力結果は順序が保証されません。
ゴルーチンとメインゴルーチンは、それぞれ独自の実行フローを持ちます。ゴルーチンは非同期に実行され、指定されたタイミングで実行が開始されることに注意してください。
ゴルーチンの利点は、並行処理を容易に実現できることです。複数のゴルーチンを使用することで、並行に実行される処理を効率的に記述できます。ただし、ゴルーチン間のデータの共有や同期には注意が必要であり、適切な同期手法(チャネル、ミューテックス、ウェイトグループなど)を使用する必要があります。
ゴルーチンを使用することで、Go言語の並行処理モデルを活用し、効率的で簡潔な並行プログラムを作成することができます。
channel
Channel(チャネル)は、Go言語の並行処理(concurrency)モデルにおいて、ゴルーチン間のデータの通信や同期を行うための仕組みです。チャネルはゴルーチン間でデータをやり取りするためのパイプラインのような役割を果たし、同期やデータの受け渡しを安全に行うことができます。
チャネルは、データ型として定義されます。例えば、chan intは整数型のデータをやり取りするチャネルを表します。チャネルはmake()関数を使用して作成し、ゴルーチン間でデータを送受信するための演算子(<-)を使用します。
以下に、チャネルの基本的な使用例を示します。
package main
import "fmt"
func main() {
// int型のチャネルを作成
ch := make(chan int)
// ゴルーチン内でデータを送信
go sendData(ch)
// メインゴルーチンでデータを受信
receiveData(ch)
}
func sendData(ch chan<- int) {
// データをチャネルに送信
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func receiveData(ch <-chan int) {
// チャネルからデータを受信
for {
data, ok := <-ch
if !ok {
// チャネルがクローズされたらループを終了
break
}
fmt.Println(data)
}
}
この例では、sendData関数とreceiveData関数がそれぞれ別のゴルーチンで実行され、チャネルを介してデータの送受信が行われます。
sendData関数では、chチャネルに0から4までのデータを送信します。チャネルにデータを送信するには、<-演算子を使用してch <- dataのように書きます。
receiveData関数では、chチャネルからデータを受信し、受信したデータを表示します。チャネルからデータを受信するには、<-演算子を使用してdata := <-chのように書きます。
また、close(ch)を使用してチャネルを明示的にクローズすることができます。クローズされたチャネルからのデータ受信は、data, ok := <-chの形式で行い、okの値がfalseとなった場合にはチャネルがクローズされたことを示します。
チャネルはデータの同期やゴルーチン間の通信を行うための重要なツールであり、ゴルーチン間の安全なデータ共有や処理の順序制御に役立ちます。
例2
package main
import (
"fmt"
"time"
)
func main() {
// string型のチャネルを作成
ch := make(chan string)
// ゴルーチン内で非同期にデータを送信
go sendData(ch)
// メインゴルーチンでデータを受信し表示
for {
// チャネルからデータを受信
data, ok := <-ch
if !ok {
// チャネルがクローズされたらループを終了
break
}
fmt.Println(data)
}
fmt.Println("メインゴルーチン終了")
}
func sendData(ch chan<- string) {
// データをチャネルに送信
for i := 1; i <= 5; i++ {
time.Sleep(time.Second) // 1秒待機
ch <- fmt.Sprintf("データ %d", i)
}
close(ch) // チャネルをクローズ
}
この例では、sendData関数からchチャネルを介して非同期に文字列データを送信し、メインゴルーチンで受信して表示します。
sendData関数では、chチャネルに1から5までのデータを送信します。データの送信前にtime.Sleep(time.Second)を使って1秒待機しています。
メインゴルーチンでは、チャネルからのデータ受信を無限ループで行っています。受信したデータを表示し、okの値がfalseになった場合にループを終了します。
この例では、ゴルーチンとメインゴルーチンの間でデータの送受信が行われ、チャネルを使ってデータの同期と通信を実現しています。ゴルーチンが非同期にデータを送信し、メインゴルーチンが受信して表示することで、データのフローを制御しています。