2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Swift] 複数の非同期処理を並列に行う

Posted at

はじめに

複数の非同期処理を走らせて、全ての処理が完了したタイミングで特定の処理を行った時の内容です。
これは、配列の中のそれぞれ値に対して、API通信を非同期に実行し、すべてが完了したタイミングでUIに反映させようとした時のお話です。

非同期処理

以下のような非同期処理を作成します。
ランダムな数値を生成することで、処理が完了するタイミングがバラバラになるように設定しています。

func asyncAfter(number: Int, completion: @escaping (_ number: Int, _ interval: Double) -> Void) {
    print("#\(number) Start")
    let interval  = TimeInterval(arc4random() % 100 + 1) / 100
    DispatchQueue.global().asyncAfter(deadline: .now() + interval) {
        completion(number, interval)
    }
}

非同期処理を並列に実行

まず、DispatchGroup()を作成します。
そして、それぞれの値に対して非同期処理を実行する際に.enter()を呼び、処理が完了したタイミングで.leave()を呼びます。
そうすると、全ての処理が完了したタイミングで、.notify()の中の処理が実行されるという仕組みです。

func asyncTask() {
    let dispatchGroup = DispatchGroup()
    for i in 0 ..< 5 {
        dispatchGroup.enter()
        asyncAfter(number: i) { (number: Int, interval: Double) -> Void in
            defer { dispatchGroup.leave() }
            print("#\(number) completed (interval: \(interval))")
        }
    }

    dispatchGroup.notify(queue: .main) {
        // 全ての処理が完了した時に呼ばれる
        print("all process completed!")
    }
}

出力結果

実際に実行してみると、出力結果は以下のようになりました。想定通りの挙動になってそうですね。
まず、for文によってそれぞれの値に対して非同期処理が、Startします。
その後、インターバルの短い処理からcompletedされていき、全ての処理が完了したタイミングで、.notify()内の処理が呼ばれていることが分かります。

#0 Start
#1 Start
#2 Start
#3 Start
#4 Start
#0 completed (interval: 0.18)
#3 completed (interval: 0.57)
#4 completed (interval: 0.6)
#1 completed (interval: 0.67)
#2 completed (interval: 0.93)
all process completed!

コード全文

以下、コードの全文です。

func asyncTask() {
    let dispatchGroup = DispatchGroup()
    for i in 0 ..< 5 {
        dispatchGroup.enter()
        asyncAfter(number: i) { (number: Int, interval: Double) -> Void in
            defer { dispatchGroup.leave() }
            print("#\(number) completed (interval: \(interval))")
        }
    }

    dispatchGroup.notify(queue: .main) {
        // 全ての処理が完了した時に呼ばれる
        print("all process completed!")
    }
}

func asyncAfter(number: Int, completion: @escaping (_ number: Int, _ interval: Double) -> Void) {
    print("#\(number) Start")
    let interval  = TimeInterval(arc4random() % 100 + 1) / 100
    DispatchQueue.global().asyncAfter(deadline: .now() + interval) {
        completion(number, interval)
    }
}

参考

2
4
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
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?