0
0

Goroutineとは?Go言語の並行処理を理解しよう

Go言語(Golang)は、Googleによって開発されたオープンソースのプログラミング言語で、シンプルで効率的な並行処理をサポートしています。その中でも特に注目すべき機能が「Goroutine」です。この記事では、Goroutineの基本概念、使い方、そしてその利点について詳しく解説します。

Goroutineとは

Goroutineは、Go言語における軽量なスレッドのようなものです。Goroutineを使うことで、プログラムの複数の部分を同時に実行することができます。Goroutineは非常に軽量で、数千から数百万のGoroutineを同時に実行することが可能です。

Goroutineの特徴

  1. メモリ消費:
    Goroutineはカーネルスレッドに比べて非常に少ないメモリしか消費しません。カーネルスレッドは1MB程度のスタックを必要としますが、Goroutineは2KBのスタックだけが必要です。
  2. 生成・破壊コスト:
    GoroutineはGoランタイムから生成と破壊が行われるため、コストが低いです。
  3. コンテキストスイッチ:
    GoroutineはM:Nモデルを採用しており、マルチタスキングによるコンテキストスイッチが抑えられ、マルチコアが活用できます。

Goroutineの基本的な使い方

Goroutineを使うのは非常に簡単です。関数呼び出しの前にgoキーワードを付けるだけで、その関数が新しいGoroutineとして実行されます。
基本的な例

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello, World!")
}

func main() {
    go sayHello() // Goroutineとして関数を実行
    time.Sleep(1 * time.Second) // メイン関数が終了しないように待機
}

このプログラムでは、sayHello関数がGoroutineとして実行されます。time.Sleepを使ってメイン関数が終了しないようにしている点に注意してください。

複数のGoroutine

複数のGoroutineを同時に実行することも簡単です。

package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
        time.Sleep(100 * time.Millisecond)
    }
}

func printLetters() {
    for i := 'A'; i <= 'E'; i++ {
        fmt.Printf("%c\n", i)
        time.Sleep(150 * time.Millisecond)
    }
}

func main() {
    go printNumbers()
    go printLetters()
    time.Sleep(1 * time.Second)
}

このプログラムでは、printNumbersとprintLettersの2つの関数がそれぞれGoroutineとして実行され、数字と文字が並行して出力されます。

Goroutineの利点

  1. 軽量性
    Goroutineは非常に軽量で、少量のメモリしか消費しません。これは、GoランタイムがGoroutineのスケジューリングを効率的に行うためです。数千から数百万のGoroutineを同時に実行することが可能です。
  2. シンプルな並行処理
    Goroutineを使うことで、複雑なスレッド管理を行うことなく、簡単に並行処理を実現できます。goキーワードを使うだけで、新しいGoroutineを作成できます。
  3. チャネルによる通信
    Go言語には、Goroutine間での通信を簡単に行うための「チャネル」という機能があります。チャネルを使うことで、Goroutine間でデータを安全にやり取りすることができます。
    チャネルの基本的な使い方
    以下は、チャネルを使った基本的な例です。
package main

import (
    "fmt"
)

func sum(a []int, c chan int) {
    total := 0
    for _, v := range a {
        total += v
    }
    c <- total // チャネルに結果を送信
}

func main() {
    a := []int{1, 2, 3, 4, 5}
    c := make(chan int)
    go sum(a, c)
    result := <-c // チャネルから結果を受信
    fmt.Println(result)
}

このプログラムでは、sum関数がGoroutineとして実行され、計算結果がチャネルを通じてメイン関数に送信されます。

Goroutineのスケジューリング

GoroutineのスケジューリングはGoランタイムによって管理されます。Goランタイムは、利用可能なリソース(CPUコアやスレッド)を最大限に活用し、全てのGoroutineが均等に処理されるようにします。

M:Nスケジューリング

Goランタイムでは、M:Nスケジューリングモデルが採用されています。これは、M個のGoroutineをN個のカーネルスレッドにマッピングすることを意味し、1つのカーネルスレッドが複数のGoroutineを切り替えながら実行することができます。

スケジューリングの透過性

Goを使用する開発者は、スケジューリングの詳細を気にする必要がありません。プログラマは単にgoキーワードを使ってGoroutineを起動するだけで、後はランタイムが適切にスケジューリングを行います。

まとめ

Goroutineは、Go言語の強力な並行処理機能の一つです。軽量でシンプルなGoroutineを使うことで、効率的な並行処理を実現できます。さらに、チャネルを使うことで、Goroutine間の通信も簡単に行うことができます。

参考文献:

0
0
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
0
0