Swiftでネストされたforループを最適化する

ディエゴメン

の白いピクセルをカウントするこのメソッドを取得しましたUIImage。すべてのピクセルを調べて、見つかった白いピクセルごとにカウンターを増やす必要があります。パフォーマンスを改善しようとしていますが、これ以上のアプローチは見つかりません。何か案は?

func whitePixelCount() -> Int {
    let width = Int(image.size.width)
    let height = Int(image.size.height)
    var counter = 0
    for x in 0..<(width*scale) {
        for y in 0..<(height*scale) {
            // We multiply per 4 because of the 4 channels, RGBA, but later we just use the Alpha
            let pixelIndex = (width * y + x) * 4

            if pointer[pixelIndex + Component.alpha.rawValue] == 255 {
                counter += 1
            }
        }
    }
    return counter
}
  • Component.alpha.rawValue に等しい 3
  • scale です Int(image.scale)
  • pointer から来た:

    guard let cfdata = self.image.cgImage?.dataProvider?.data,
        let pointer = CFDataGetBytePtr(cfdata) else {
            return nil
    }
    
ロブ

いくつかの観察:

  1. 最適化されていないデバッグビルドではなく、最適化された/リリースビルドを使用していることを確認してください。私のデバイスでは、デバッグビルドは12メガピクセルの画像を処理するのに約4秒かかりますが、リリースビルドは0.3秒かかります。

  2. forループがある場合は、それを並列化して、CPU上のすべてのコアを活用できます。ストライドアルゴリズムを使用してこれを行うことにより、forループはほぼ4倍高速になりました。

    それは素晴らしいことのように聞こえますが、残念ながら、問題は画像を処理するための0.3秒の問題であり、そのほとんどは画像バッファの準備でした。(ここで、あなたの例では、事前定義されたピクセルバッファーに再レンダリングしていません。これは、少し危険なIMHOであるため、このオーバーヘッドがない可能性があります。ただし、10ミリ秒以上の違いは一般的に観察できません。何百もの画像を処理している場合を除きます。)実際のforループは、経過時間の16ミリ秒しか占めていませんでした。したがって、これを4ミリ秒に短縮すると、ほぼ4倍高速になりますが、ユーザーの観点からは重要ではありません。

とにかく、私の元の答えで、下を歩き回る並列アルゴリズムを自由に見てください。


forループパフォーマンスを改善するための非常に簡単なアプローチの1つconcurrentPerform、ルーチンを並列するために使用することです。

たとえば、これは並列化されていないルーチンです。

var total = 0

for x in 0..<maxX {
    for y in 0..<maxY {
        if ... {
            total += 1
        }
    }
}

print(total)

あなたはそれを並列化することができます

  • 外側のループを画像の行にしたいのでxyループループを反転します。アイデアは、各スレッドが連続したメモリブロックで動作するようにするだけでなく、「キャッシュスロッシング」を回避するためにオーバーラップの量を最小限に抑えることです。したがって、次のことを考慮してください。

    for y in 0..<maxY {
        for x in 0..<maxX {
            if ... {
                total += 1
            }
        }
    }
    

    上記を実際に使用するつもりはありませんが、次のステップでモデルとして使用します。

  • 外側のforループ(現在はy座標)をconcurrentPerform次のように置き換えます

    var total = 0
    
    let syncQueue = DispatchQueue(label: "...")
    
    DispatchQueue.concurrentPerform(iterations: maxY) { y in
        var subTotal = 0
        for x in 0..<maxX {
            if ... {
                subTotal += 1
            }
        }
        syncQueue.sync {
            total += subTotal
        }
    }
    
    print(total)
    

したがって、アイデアは次のとおりです。

  • 外側のforループをconcurrentPerform;に置き換えます
  • むしろ更新を試みるよりtotalのすべての反復のためにx持って、subTotal各スレッドのみ更新の変数total(この共有リソースのための複数のスレッドからの競合を最小化する)の端部に、そして
  • いくつかの同期メカニズム(ここではシリアルキューを使用しましたが、どの同期メカニズムでも機能します)を使用して更新totalし、スレッドセーフを確保します。

私は例をできるだけ単純にしようとしていましたが、実行できる他の最適化もあります。

  • 同期技術が異なれば、パフォーマンスも異なります。たとえば、プロトコル拡張でメソッドをNSLock定義するsyncことで(ロックを使用するための優れた安全な方法を提供するために)次のように使用できます(従来の通念では遅いと言われていますが、最近のベンチマークでは、多くのシナリオでGCDよりもパフォーマンスが向上する可能性があります)。そう:

    // Adapted from Apple’s `withCriticalSection` code sample
    
    extension NSLocking {
        func sync<T>(_ closure: () throws -> T) rethrows -> T {
            lock()
            defer { unlock() }
            return try closure()
        }
    }
    

    次に、次のようなことができます。

    let lock = NSLock()
    
    DispatchQueue.concurrentPerform(iterations: maxY) { y in
        var subTotal = 0
        for x in 0..<maxX {
            if ... {
                subTotal += 1
            }
        }
        lock.sync {
            total += subTotal
        }
    }
    
    print(total)
    

    必要な同期メカニズムを自由に試してください。ただし、total複数のスレッドからアクセスする場合は、スレッドセーフな方法でアクセスするようにしてください。スレッドセーフを確認したい場合は、一時的に「スレッドサニタイザー」をオンにしてください。

  • 各スレッドで十分な作業がない場合(たとえばmaxX、それほど大きくない場合、またはこの場合のようにアルゴリズムが非常に高速である場合)、並列化されたルーチンのオーバーヘッドが、計算に複数のコアを含めることの利点を相殺し始める可能性があります。したがってy、各反復での複数の行を「ストライド」できます。例えば:

    let lock = NSLock()
    
    let stride = maxY / 20
    let iterations = Int((Double(height) / Double(stride)).rounded(.up))
    
    DispatchQueue.concurrentPerform(iterations: iterations) { i in
        var subTotal = 0
        let range = i * stride ..< min(maxY, (i + 1) * stride)
        for y in range {
            for x in 0 ..< maxX {
                if ... {
                    subTotal += 1
                }
            }
        }
    
        lock.sync { count += subTotal }
    }
    

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Swiftでネストされたforループを最適化する

分類Dev

Pythonでネストされたforループを最適化する方法

分類Dev

Rubyでネストされたループを最適化する

分類Dev

IF条件でネストされたwhileループを最適化する

分類Dev

rのネストされたforループを最適化する

分類Dev

rの行列で計算するためにネストされたforループを最適化する

分類Dev

ネストされたforループとjavascriptのifステートメントを最適化する

分類Dev

ネストされたPythonforループを最適化しますか?

分類Dev

リストの付属物を含むネストされたforループを最適化する方法は?

分類Dev

最適化ループ/ネストされたループ

分類Dev

これらのネストされたループを最適化する方法は?

分類Dev

ネストされたforループを使用して関数を最適化する方法

分類Dev

ネストされたループでの発生数をカウントするためにC#コードを最適化する

分類Dev

ネストされたifステートメント内のネストされたforループを最適化する

分類Dev

ネストされたforループの最適化

分類Dev

ネストされたループの最適化の改善

分類Dev

GCCを使用したC / C ++のループ内のネストされたifステートメントを最適化する

分類Dev

Java 8でハッシュマップを作成するために使用されるこれらのネストされたforループを最適化する最良の方法は何ですか?

分類Dev

forループネストされた内部条件コードを最適化します

分類Dev

ネストされたforループの時間計算量を最適化するために、重複する計算を避けます

分類Dev

Python関数でネストされたwhileループを適用する方法

分類Dev

ネストされたForループの代替または最適化

分類Dev

ネストされたforループアルゴリズム、JavaScriptの最適化

分類Dev

大規模なデータセットのネストされた構造に配列ごとにグループを最適化する

分類Dev

最適化されたGoogleマップルートを編集する

分類Dev

カスタムテーブルタイプを使用せずに、ネイティブにコンパイルされたストアドプロシージャでメモリに最適化されていないテーブルを使用する

分類Dev

Pythonでビルドして印刷する方法-ループによって生成された最適化された値のリストをGEKKO?

分類Dev

ブルートフォース攻撃でネストされた4つのfor()ループのセットを最適に「並列化」するにはどうすればよいですか?

分類Dev

関数スキャンとネストされたループの見積もりが遅くて悪い場合にPostgreSQLクエリを最適化する

Related 関連記事

  1. 1

    Swiftでネストされたforループを最適化する

  2. 2

    Pythonでネストされたforループを最適化する方法

  3. 3

    Rubyでネストされたループを最適化する

  4. 4

    IF条件でネストされたwhileループを最適化する

  5. 5

    rのネストされたforループを最適化する

  6. 6

    rの行列で計算するためにネストされたforループを最適化する

  7. 7

    ネストされたforループとjavascriptのifステートメントを最適化する

  8. 8

    ネストされたPythonforループを最適化しますか?

  9. 9

    リストの付属物を含むネストされたforループを最適化する方法は?

  10. 10

    最適化ループ/ネストされたループ

  11. 11

    これらのネストされたループを最適化する方法は?

  12. 12

    ネストされたforループを使用して関数を最適化する方法

  13. 13

    ネストされたループでの発生数をカウントするためにC#コードを最適化する

  14. 14

    ネストされたifステートメント内のネストされたforループを最適化する

  15. 15

    ネストされたforループの最適化

  16. 16

    ネストされたループの最適化の改善

  17. 17

    GCCを使用したC / C ++のループ内のネストされたifステートメントを最適化する

  18. 18

    Java 8でハッシュマップを作成するために使用されるこれらのネストされたforループを最適化する最良の方法は何ですか?

  19. 19

    forループネストされた内部条件コードを最適化します

  20. 20

    ネストされたforループの時間計算量を最適化するために、重複する計算を避けます

  21. 21

    Python関数でネストされたwhileループを適用する方法

  22. 22

    ネストされたForループの代替または最適化

  23. 23

    ネストされたforループアルゴリズム、JavaScriptの最適化

  24. 24

    大規模なデータセットのネストされた構造に配列ごとにグループを最適化する

  25. 25

    最適化されたGoogleマップルートを編集する

  26. 26

    カスタムテーブルタイプを使用せずに、ネイティブにコンパイルされたストアドプロシージャでメモリに最適化されていないテーブルを使用する

  27. 27

    Pythonでビルドして印刷する方法-ループによって生成された最適化された値のリストをGEKKO?

  28. 28

    ブルートフォース攻撃でネストされた4つのfor()ループのセットを最適に「並列化」するにはどうすればよいですか?

  29. 29

    関数スキャンとネストされたループの見積もりが遅くて悪い場合にPostgreSQLクエリを最適化する

ホットタグ

アーカイブ