LoginSignup
20
6

More than 3 years have passed since last update.

【Golang】Go言語基礎 Goroutineとは?

Last updated at Posted at 2020-09-27

本日はgoroutineについて勉強しましたのでここでアウトプットさせて頂きます!

Goroutineとは?

Goroutineとはgoステートメントで関数を指定することで、並行実行されるものです!

まずは普通の関数を書いてみます。


package main

import (
    "fmt"
    "time"
)

func goroutine(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func hoge(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    goroutine("world")
    hoge("hello")
}
実行結果
world
world
world
world
world
hello
hello
hello
hello
hello

これは、普通に上から関数が0.1秒ごとに実行されているだけですね。

これを並行実行するためには、関数名の前にgoを付けるだけで並行実行できます。


(同じなので省略)

func main() {
    go goroutine("world")
    hoge("hello")
}
実行結果
hello
world
world
hello
world
hello
hello
world
world
hello

並行実行しているので出力が混じった状態になります。
このように goステートメントを指定するだけで並行実行が簡単に実現できます。

ここで、timeの部分をコメントアウトしてみるとどうなるでしょうか?


package main

import (
    "fmt"
)

func goroutine(s string) {
    for i := 0; i < 5; i++ {
        //time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func hoge(s string) {
    for i := 0; i < 5; i++ {
        //time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go goroutine("world")
    hoge("hello")
}
実行結果
hello
hello
hello
hello
hello

timeの部分をコメントアウトすると、helloしか出力されなくなりました。
これは、並列処理でgoroutineスレッドが生成されても、先にmain関数の処理が終わってしまったため、
goroutine関数が実行されずに終わってしまったからです。

このようにgorutineの処理が終わらなくてもプログラムのコードは終了してしまうということを覚えておきましょう。

ではこれを避けるためにはどうすればよいか?

sync.WaitGroupというのを使います。

sync.WaitGroup


package main

import (
    "fmt"
    "sync"
)

func goroutine(s string, wg *sync.WaitGroup) {
    for i := 0; i < 5; i++ {
        fmt.Println(s)
    }
    wg.Done()
}

func hoge(s string) {
    for i := 0; i < 5; i++ {
        fmt.Println(s)
    }
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go goroutine("world", &wg)
    hoge("hello")
    wg.Wait()
}

このようにwgという変数を宣言してwg.Add(1)で一個の並列処理があるということを記述し、
goroutine関数へwgのアドレスを引数で渡してあげます。

そして、wg.Wait()と書いてあげることで、gorutine関数のwg.Done()が呼ばれるまで処理が終わるのを待ってくれます。
このように書くことでgoroutine関数が実行されずに処理が終わってしまうことを回避することができます。

ちなみに、wg.Add(1)でgoroutineの処理が終わるのを待っているので、 wg.Done()をコメントアウトするとエラーになります。
wg.Addしたらwg.Done()を呼び出して処理が完了したことを示す必要があります。

またgoroutine関数は以下のように書くこともできます。


func goroutine(s string, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        fmt.Println(s)
    }
}

deferステートメントを使うとその関数の処理が終わった後にwg.Done()が実行されるので、このように書くこともできるのです。

最後まで読んでいただきありがとうございます!

間違いや感想などありましたらコメントいただけると嬉しいです!!

20
6
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
20
6