muapps

iOSアプリ開発で得られた知見をメモ代わりに投稿します。

Dispatchqueueの挙動整理

以下の記事を参考にDispatchqueueの種類ごとにPlaygroundで実行してみた

dev.classmethod.jp

実行環境:
Xcode13.0
Swift5.2

メインキュー

sync(同期)

// メインキューは直列(前のタスクが完了次第、次のタスクが実行される)
let mainQueue = DispatchQueue.main
// syncを使うと呼び出し元がブロックされる
print("start")
for i in 0...5 {
    mainQueue.sync() {
        print(i)
    }
}
print("end")

実行結果

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

async(非同期)

// 非同期なので呼び出し元がブロックされずstart、endが最初に出力される
// 直列なので番号は順番に出力される
print("start")
for i in 0...5 {
    mainQueue.async() {
        sleep(1)
        print(i)
    }
}
print("end")

実行結果

start
end
0
1
2
3
4
5

グローバルキュー

sync(同期)

// グローバルキューは並列(前のタスクの処理状況に関わらず、次のタスクが実行される)
let grobalQueue = DispatchQueue.global(qos: .default)

// 同期なので呼び出し元がブロックされてendが最後に出力される
// 並列だが同期なので番号は順番に出力される
print("start")
for i in 0...5 {
    grobalQueue.sync() {
        sleep(1)
        print(i)
    }
}
print("end")

実行結果

start
0
1
2
3
4
5
end

async(非同期)

// 非同期なので呼び出し元がブロックされずstart、endが最初に出力される
// 並列なので番号が出力される順番はバラバラ
print("start")
for i in 0...5 {
    grobalQueue.async() {
        sleep(1)
        print(i)
    }
}
print("end")

実行結果

start
end
4
2
3
0
1
5

自分でDispatchQueueを用意する場合

// 直列
let serialQueue = DispatchQueue(label: "serialQueue")
// 並列
let parallelQueue = DispatchQueue(label: "parallelQueue", attributes: .concurrent)

同期および非同期での実行結果はメインキュー、グローバルキューの結果から推察できる通り。
メインキューではエラーになったが直列で同期の場合は以下のようになる。

print("start")
for i in 0...5 {
    serialQueue.sync() {
        sleep(1)
        print(i)
    }
}
print("end")

実行結果

start
0
1
2
3
4
5
end