0

私はMacOS上で動作するSwiftアプリケーションを持っています。イメージをバッチ処理します。私は、これらのイメージがどれだけ大きくなるのか、そして私のアプリケーションがどのハードウェア上で実行されるのかを事前に知っていません。これらは両方ともユーザーに依存しています。メモリを使い果たすことなく、できるだけMacOSアプリケーションのタスクを並列化するにはどうすればよいですか?

GCDを使用して、画像の処理を並列化して、実際にスループットを向上させることができます。

しかし、場合によっては、並列化が高すぎると、ユーザーが高解像度の画像を処理すると、並列化が多すぎるメモリ圧迫を引き起こし、システムのパフォーマンスが非常に悪くなります。

私はRAM内で作業負荷を維持しながら並列化を最大化する速度で「並列タスクプロセッサを使用する」方法を見つけたいと思います(&のスワッピングを呼び出すトリガーはありません)。ディスクIO)。

これを行う方法に関するアイデアはありますか?

+0

どのように並列化していますか?つまり、各イメージを使用可能なコアに分割するか、複数のイメージを並行して処理しますか? –

+0

複数の画像を並行して処理します。私が1つの画像のために作業を並列化できれば、この問題はそれほど重要ではないでしょう。おそらく、私はその道にもっと努力する必要があるかもしれません(1つの画像だけを処理する場合には待ち時間が短くなるという利点もあります)。 – BearOverflow

+0

更新:私が恐れていたことは真実に終わりました。並列化できる部分は並列化のメリットがありません。並列タスクを作成するオーバーヘッドは、CPU効率の利点を取り除きます。この部分の最適な並列化係数は2です(これ以上の利得は得られません)。これは素晴らしいことですが、名目上のユースケースではない大量の画像(8192x8192)との違いが始まります。名目上のユースケースの場合、マイナーな改善はコードの複雑さを保証するものではないと私は思う。だから問題は本当にまだ立っている。 – BearOverflow

答えて

0

私はトークンバケットタイプのシングルトンを実装しました。シングルトンは、メモリ要件に基づいてアドミッションコントロールを処理します。 RAMの80%が私のアプリケーションで使用できるように初期化されます。

let memoryGate = MemoryGate(maxBytes: ProcessInfo.processInfo.physicalMemory*8/10) 

誰かがメモリ集約型操作を実行したい場合、そのメモリから要求()する必要があります。十分なメモリがない場合、コールはブロックされるまでブロックされます。終了後、スレッドはメモリーを解放()しなければなりません。

コード:

class MemoryGate { 

    private let maxBytes : UInt64 
    private var availableBytes : Int64 

    private let cv = NSCondition() 

    init(maxBytes: UInt64) { 
     self.maxBytes = maxBytes 
     self.availableBytes = Int64(maxBytes) 
     Log.debug?.message("maxBytes=\(maxBytes)") 
    } 

    public func request(amount: UInt64) { 
     Log.debug?.message("Resquesting \(amount) bytes") 
     cv.lock() 

     // If the amount is bigger than the max allowed, no amount of waiting is going 
     // to help, so we go through and let the other smaller jobs be held back until 
     // memory is freed 
     if (amount <= maxBytes) { 
      while (availableBytes < Int64(amount)) { 
       cv.wait() 
      } 
     } 

     availableBytes -= Int64(amount) 

     Log.debug?.message("Got \(amount) bytes. availableBytes=\(availableBytes)") 
     cv.unlock() 
    } 

    public func release(amount: UInt64) { 
     cv.lock() 
     availableBytes += Int64(amount) 
     Log.debug?.message("Released \(amount) bytes. availableBytes=\(availableBytes)") 
     cv.broadcast() 
     cv.unlock() 
    } 
} 
0

メモリ圧力イベントのためのGCD dispatch sourceがあります。あなたのコードがどのように構造化されているかはわかりませんが、DISPATCH_MEMORYPRESSURE_WARNイベントが発生するまで並列タスクを作成してから、タスクをやめたり、

+0

バッチ処理では、ユーザーが処理したい写真のリスト(500としましょう)を取得し、GCDで管理されているDispatchQueueにそれらをスローする必要があるため、これはちょっと難しいです。おそらく、GCDは利用可能なCPUリソースをどのように使用するのかをよく知っているので、GCDのためにすべてを投入してその仕事をすることになっています。しかし、いったん彼らがいたら、彼らは人生を動かす:私は彼らを取り戻すことはできないと思う。それで、彼らはすべて、メモリの割り当てを開始します。私がDISPATCH_MEMORYPRESSURE_WARNを得るまでには、それは遅すぎます - タスクはすでにGCDに送られて処理されています。 – BearOverflow

関連する問題