Avatar
Avatar
Taketo Sano
並列処理の実装に関してアドバイスを頂きたいので質問させて下さい 🙇 以下のコードは実際に使っているコードを簡略化したものです。 find の処理を並列化するために DispatchQueue.concurrentPerform を使っています.find は現在の results も使うため、各スレッドで results のコピー localResults を作り、find の結果、他のスレッドによって変更されていなければ results に追加、変更されていれば localResults を更新してやり直し、という感じの処理になっています。 実際のケースでは targets は膨大な量があり、find もそこそこ見つかるので、 localResults のコピーを更新があるごとに作っているのがパフォーマンスに影響しています。理想的には localResults を作らず、どれかのスレッドが result を見つけたら、他のスレッドが find を終わらすのを待った上で、同期的に(複数ありうる) result の中かから一番いいものを選んで results に追加し、それが終わったらまたみんなで find を続ける、という感じにしたいのですが、どう実装したらいいものか迷っています。 最近よく聞く async/await を使うとキレイにできたりするのかなーとか思ってまして、もし良い方法があれば教えて下さい 🙇 import Dispatch var targets = Set(0 ..< 10000) var results: [Int: Int] = [:] let atomic = DispatchQueue(label: "atomic", qos: .userInteractive) DispatchQueue.concurrentPerform(iterations: 4) { _ in // create local copy var localResults = atomic.sync { results } while true { let next = atomic.sync { targets.popFirst() } guard let i = next else { break // all targets popped, exit loop. } if let result = find(in: i, currentResults: localResults) { atomic.sync { // update results if not updated by other threads. if localResults.count == results.count { results[i] = result } else { // otherwise retry i. targets.insert(i) } } } atomic.sync { // update local copy if necessary if localResults.count != results.count { localResults = results } } } } // parallelized function func find(in i: Int, currentResults: [Int: Int]) -> Int? { i % 100 == 0 ? i : nil } print(results.count)
Swift 5.5 を前提にするのであれば、 resultstargets を Actor で守りながら、 findTaskGroup で並行に走らせるのが良いように思います。