🍒

【Swift】Concurrency (async/await)

2024/07/18に公開

並行処理とは

「並行処理」とは、コンピューターにいくつかの作業を同時にさせる方法です。

例えば料理を例に考えてみます。料理の手順には、

  1. 野菜を切る
  2. 肉を切る
  3. 鍋に水を入れる
  4. 鍋に野菜を入れて煮る

などがあります。

これを順番に一つずつやっていたら、料理ができるまでにすごく時間がかかってしまいますね。
しかし【野菜を切る】【肉を切る】【鍋に水を入れる】を複数の人が同時で行い、それらが終わったら、【鍋に野菜を入れて煮る】を行えば、より早く料理が完成するはずです。
このような同時並行で処理を行うことが「並行処理」です。

1. asyncについて

asyncは「非同期」という意味です。これは「同時に何かをする」というイメージです。

2. awaitについて

awaitは「待つ」という意味です。これを使うと、「この作業が終わるまで他の作業を待つ」という指示をコンピューターに出せます。具体的には、関数がバックグラウンドで実行される作業を終えて、結果を返すまでプログラムの実行を一時停止することを指示します。

コードの例

先ほどの料理の例にサンプルコードを紹介します。

import Foundation

// 野菜を切る作業を模擬する関数
func chopVegetables() async {
    print("野菜を切る開始")
    try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待機
    print("野菜を切る完了")
}

// 肉を切る作業を模擬する関数
func chopMeat() async {
    print("肉を切る開始")
    try? await Task.sleep(nanoseconds: 2_000_000_000) // 2秒待機
    print("肉を切る完了")
}

// 鍋に水を入れる作業を模擬する関数
func boilWater() async {
    print("鍋に水を入れる開始")
    try? await Task.sleep(nanoseconds: 1_500_000_000) // 1.5秒待機
    print("鍋に水を入れる完了")
}

// 鍋に野菜を入れて煮る作業を模擬する関数
func cookVegetables() async {
    print("鍋に野菜を入れて煮る開始")
    try? await Task.sleep(nanoseconds: 3_000_000_000) // 3秒待機
    print("鍋に野菜を入れて煮る完了")
}

// メイン処理
@main
struct Main {
    static func main() async {
        print("料理開始")

        // 並行して行う準備作業を始める
        async let chopVegetablesTask = chopVegetables() // 野菜を切る作業を始める
        async let chopMeatTask = chopMeat() // 肉を切る作業を始める
        async let boilWaterTask = boilWater() // 鍋に水を入れる作業を始める

        // すべての準備作業が終わるのを待つ
        // どれが一番最初に終わるかはわからない。boilWaterTaskが最初に終わっても、それ以外のタスクが終わるのを待ってからcookVegetables()へ。
        await chopVegetablesTask // 野菜を切る作業が終わるまで次の行に進むのを待つ
        await chopMeatTask // 肉を切る作業が終わるまで次の行に進むのを待つ
        await boilWaterTask // 鍋に水を入れる作業が終わるまで次の行に進むのを待つ

        // 次の手順に進む
        await cookVegetables() // 鍋に野菜を入れて煮る作業を始める

        print("料理完了") // 料理が全部終わったことを表示
    }
}

Discussion