🔬

Swift界の「トンネルを抜けたら雪国」こと「awaitを抜けたら別スレッド」調査隊

2024/03/29に公開

Swiftエンジニアにとって、「トンネルを抜けたら雪国」に似たフレーズと言えばこれである。

awaitを抜けたら別スレッドの可能性があります。

今日、我々はこれを調査する。

書かれている場所

この有名なフレーズが書かれているのはここである。

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency

コード

調査する。

import Foundation

var result: [(Int, Thread)] = []

for a in 1...20 {
    Task.detached {
        b(a: a, t: Thread.current)
        try? await Task.sleep(nanoseconds: UInt64(Int.random(in: 20...40)))
        b(a: a, t: Thread.current)
    }
}

func b(a: Int, t: Thread) {
    DispatchQueue.main.async {
        result.append((a, t))
    }
}

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    result = result.sorted(by: {
        $0.0 < $1.0
    })
    
    for r in result {
        print(r)
    }
}

結果(例)

(1, <NSThread: 0x6000019e0b00>{number = 4, name = main})
(1, <NSThread: 0x6000019eee80>{number = 9, name = main})
(2, <NSThread: 0x6000019e4ec0>{number = 2, name = main})
(2, <NSThread: 0x6000019e0b00>{number = 4, name = main})
(3, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(3, <NSThread: 0x6000019e4ec0>{number = 2, name = main})
(4, <NSThread: 0x6000019e1b40>{number = 6, name = main})
(4, <NSThread: 0x6000019ecec0>{number = 7, name = main})
(5, <NSThread: 0x6000019ecec0>{number = 7, name = main})
(5, <NSThread: 0x6000019eee80>{number = 9, name = main})
(6, <NSThread: 0x6000019e1880>{number = 8, name = main})
(6, <NSThread: 0x6000019eee80>{number = 9, name = main})
(7, <NSThread: 0x6000019eee80>{number = 9, name = main})
(7, <NSThread: 0x6000019e1880>{number = 8, name = main})
(8, <NSThread: 0x6000019e1740>{number = 10, name = main})
(8, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(9, <NSThread: 0x6000019e1880>{number = 8, name = main})
(9, <NSThread: 0x6000019e0b00>{number = 4, name = main})
(10, <NSThread: 0x6000019e1740>{number = 10, name = main})
(10, <NSThread: 0x6000019e1b40>{number = 6, name = main})
(11, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(11, <NSThread: 0x6000019e1740>{number = 10, name = main})
(12, <NSThread: 0x6000019eee80>{number = 9, name = main})
(12, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(13, <NSThread: 0x6000019e1880>{number = 8, name = main})
(13, <NSThread: 0x6000019ecec0>{number = 7, name = main})
(14, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(14, <NSThread: 0x6000019e0b00>{number = 4, name = main})
(15, <NSThread: 0x6000019e1740>{number = 10, name = main})
(15, <NSThread: 0x6000019e1b40>{number = 6, name = main})
(16, <NSThread: 0x6000019e1880>{number = 8, name = main})
(16, <NSThread: 0x6000019eee80>{number = 9, name = main})
(17, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(17, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(18, <NSThread: 0x6000019e1740>{number = 10, name = main})
(18, <NSThread: 0x6000019e1880>{number = 8, name = main})
(19, <NSThread: 0x6000019e1ec0>{number = 5, name = main})
(19, <NSThread: 0x6000019e1740>{number = 10, name = main})
(20, <NSThread: 0x6000019e1880>{number = 8, name = main})
(20, <NSThread: 0x6000019e4ec0>{number = 2, name = main})

全体的に await を抜けると違う値になっている。(なんでnameがmainになっているのかわからないが)

考察

説明に書いてある別スレッドというのが、このプログラムで確認しているスレッドなのであれば、「確かに再開した後は違うことがあるね」となるが、問題は、 説明に書いてある別スレッドというのがなんなのか確定していないこと である。

スレッドという言葉は、実行するコード(食材)が複数と言いたい場合と、コードを実行する環境(コンロ)が複数と言いたい場合に分かれる気がするが、ここで言っているスレッドは後者の方ではないかと。

私がやっていることと推測が正しいとすると、コンロがいっぱいあって途中で切り上げたものを再開するときは別コンロで実行する場合があるのね、と解釈できるが...

さいごに

謎なところは残るが、このまま下書きに残しておいても公開することはなさそうなので、公開に踏み切った。

  • やっていることに意味がない
  • 状況によって違う

などの指摘がある場合はコメントをお願いします。

Discussion