【Swift】actor(async/await)がシミュレータで想定通りの動きをしない


注意

本記事にはシミュレータで想定通りの動きをさせる方法はありません。
詰まる前にシミュレータだけではなく実機でテストしましょうという注意喚起です。

結論

シミュレータでは扱えるスレッド数が少ないようで、想定外の処理待ちが発生する可能性があるようです。
サブスレッド(actor)を2個以上同時に使用する場合は可能であれば実機でテストして下さい。

私はシミュレータで使用出来るスレッド数の変更方法は見つけられませんでした。

シミュレータでの挙動について

検証端末

  • Mac mini 2018 (core-i3)
  • M1 Mac Mini
  • iPhone 11 Pro Max

検証内容

actorのインスタンスを2つ用意し間を開けず順にsleepを実行します。
その際のsleepの次の処理が実行されるタイミングを確認します。

※あまりにも簡単なのでソースは割愛していますが、後日追記するかもしれません。

sleepを用いる理由

sleepはスレッド1つ占有して止めることができます。
スレッド関連の待機処理では、待機中のスレッドとして他の処理にスレッド明け渡すものもあります。
その場合は待機中に他の処理が行われるため、今回の検証には適しません。

検証結果

実機 iPhone 11 Pro Max (想定通りの挙動)

2つのsleep処理は並行して処理され、sleepの次の処理はほぼ同時に行われます。

シミュレータ Mac mini

2つのsleep処理は順に行われ、sleepの次の処理はsleep分の時間が空いて処理されます。

考察

上記のことから、シミュレータではメインスレッドとサブスレッド1つまで割り当てられており、
処理上限に達した為スレッドが空くまで待機していると考えられます。

総括

actor(async/await)がシミュレータが実機とは異なる動作を行うことが分かりました。
想定の動作が行われなかった場合に、ソースを見返して悩むだけではなく、
実機で確認するということも忘れずに行うようにして下さい。

またシミュレータの問題だけでなく、端末の性能差や状態によっても引き起こされる事に注意して下さい。
並列処理を行う上では常に付き纏う問題でもあります。

しかし、過度に気にしなければならない問題はありません。
actorは待機スレッド有効に活用してくれます。
今回sleepで止めたように、1スレッド占有し続けるような重い処理でなければ問題ありません。

ブログ記事紹介

以下はactor、async、awaitに関する私のブログ記事です。
長くなりますし、他にも書いてる人は居そうなのでQiita版の記事を書くかは検討中です。