とあるきっかけで、UbuntuにSwiftをインストールし、並列処理をやってみたいと思ったのですが、うまくいかなかったのでその問題と解決方法を紹介します。
環境
自分が実行した環境は以下のとおりです。
- Ubuntu 20.04
- Swift version 5.3 (swift-5.3-RELEASE)
- Target: x86_64-unknown-linux-gnu
- CPU: Ryzen5 2600
やりたいこと
- とりあえず並列に処理を実行することを確認したい
- 数字を非同期でprintする
調べたところ、Dispatchqueue
を使うのが一般的なようでした。
Process
やThread
などもあるようですが、Dispatchqueue
はそれらを簡単に使えるようにしてものであるようなので、素直にDispatchqueue
を使うことにしました。
問題
はじめは調べて出てきたサイトのコードをそのまま写して、以下のようにしていました。
swift package init --type executable
を実行して諸々のファイルを生成し、main.swiftを以下のようにしました。
import Foundation
var value: Int = 2
DispatchQueue.main.async {
for i in 0...3 {
value = i
print("\(value) ✴️")
}
}
for i in 4...6 {
value = i
print("\(value) ✡️")
}
DispatchQueue.main.async {
value = 9
print(value)
}
しかし、実行結果は
4 ✡️
5 ✡️
6 ✡️
0 ✴️
1 ✴️
2 ✴️
3 ✴️
9
となることが望ましかったのですが、
4 ✡️
5 ✡️
6 ✡️
となってしまいました。
つまり、Dispatchqueue
に任せた部分の処理が全く実行されていません。
解決法
この原因には一つ心当たりがありました。
それはファイル単体で動かしていることでした。
多くのサイトはMacで開発しているiPhoneアプリの中で使うことを想定しています。
さらに、Swiftをファイル単体で実行するとき、以前も似たような不具合があったことを覚えていました。以下がそのときに投稿した質問です。
【Swift】Timerで繰り返し実行(定期実行)ができない
これは、アプリの中では自動で実行されるRunLoopがSwiftファイル単体で実行するときには実行されないため、不具合が起きていて、プログラムの末尾にRunLoop.current.run()
を追加することで解決しました。
どうようにして今回のプログラムにもRunLoop.current.run()
を追加してみました。
import Foundation
var value: Int = 2
DispatchQueue.main.async {
for i in 0...3 {
value = i
print("\(value) ✴️")
}
}
for i in 4...6 {
value = i
print("\(value) ✡️")
}
DispatchQueue.main.async {
value = 9
print(value)
}
RunLoop.current.run()
すると期待通りの出力がされました。
まとめ
- Swiftをアプリではなく、ファイル単体で実行するときにはRunLoopをつけると解決するかもしれない
- Dispatchqueueを使うときはRunLoopをつけよう
最後に
なにか間違いや改善点がありましたら、コメントや編集リクエストをお願いします。
ありがとうございました。