2017-09-30 5 views
1

私は、少なくとも2つの異なるコアに分散してメインスレッドを遅くするプロセスのスピードアップを図っています。コードは非同期よりも同期的にキューに入れられると高速に実行されます。それは逆ではないでしょうか?

私はこれを取り除くことができると考えている理由は、個々の操作のそれぞれが2点と浮動小数点を必要とする独立しているということです。

しかし、私の最初の刺し傷は、queue.asncqueue.syncを実行するとコードが大幅に遅く実行されているので、何故手掛かりがありません!ここで

同期

var block = UnsafeMutablePointer<Datas>.allocate(capacity: 0) 
var outblock = UnsafeMutablePointer<Decimal>.allocate(capacity: 0) 
func initialise() 
{ 
    outblock = UnsafeMutablePointer<Decimal>.allocate(capacity: testWith * 4 * 2) 

    block = UnsafeMutablePointer<Datas>.allocate(capacity: particles.count) 
} 

func update() 
{ 
    var i = 0 
    for part in particles 
    { 
     part.update() 

     let x1 = part.data.p1.x; let y1 = part.data.p1.y 
     let x2 = part.data.p2.x; let y2 = part.data.p2.x; 

     let w = part.data.size * rectScale 
     let w2 = part.data.size * rectScale 

     let dy = y2 - y1; let dx = x2 - x1 
     let length = sqrt(dy * dy + dx * dx) 
     let calcx = (-(y2 - y1)/length) 
     let calcy = ((x2 - x1)/length) 
     let calcx1 = calcx * w 
     let calcy1 = calcy * w 
     let calcx2 = calcx * w2 
     let calcy2 = calcy * w2 
     outblock[i] = x1 + calcx1 
     outblock[i+1] = y1 + calcy1 

     outblock[i+2] = x1 - calcx1 
     outblock[i+3] = y1 - calcy1 

     outblock[i+4] = x2 + calcx2 
     outblock[i+5] = y2 + calcy2 

     outblock[i+6] = x2 - calcx2 
     outblock[i+7] = y2 - calcy2 

     i += 8 
    } 
} 

を実行しているコードは、ここで私は本当にこの減速が起こっている理由は見当もつかない複数のコア

let queue = DispatchQueue(label: "construction_worker_1", attributes: .concurrent) 

let blocky = block 
let oblocky = outblock 
for i in 0..<particles.count 
{ 
    particles[i].update() 
    block[i] = particles[i].data//Copy the raw data into a thead safe format 
    queue.async { 
     let x1 = blocky[i].p1.x; let y1 = blocky[i].p1.y 
     let x2 = blocky[i].p2.x; let y2 = blocky[i].p2.x; 

     let w = blocky[i].size * rectScale 
     let w2 = blocky[i].size * rectScale 

     let dy = y2 - y1; let dx = x2 - x1 
     let length = sqrt(dy * dy + dx * dx) 
     let calcx = (-(y2 - y1)/length) 
     let calcy = ((x2 - x1)/length) 
     let calcx1 = calcx * w 
     let calcy1 = calcy * w 
     let calcx2 = calcx * w2 
     let calcy2 = calcy * w2 

     let writeIndex = i * 8 
     oblocky[writeIndex] = x1 + calcx1 
     oblocky[writeIndex+1] = y1 + calcy1 

     oblocky[writeIndex+2] = x1 - calcx1 
     oblocky[writeIndex+3] = y1 - calcy1 

     oblocky[writeIndex+4] = x2 + calcx2 
     oblocky[writeIndex+5] = y2 + calcy2 

     oblocky[writeIndex+6] = x2 - calcx2 
     oblocky[writeIndex+7] = y2 - calcy2 
    } 
} 

間でワークロードを分散での私の試みです!私はUnsafeMutablePointerを使用しているので、データはスレッドセーフであり、同時に複数のスレッドが変数を読み書きできるようにしています。

ここでは何が起こっていますか?

+0

マイナーな問題ですが、私は 'w'と' w2'の目的に従っていません。 'sqrt(dy * dy + dx * dx)'は 'hypot(dy、dx)'に置き換えることもできます。また、 'UnsafeMutablePointer'のThreading Benefitsが' Array'のようにSwiftierに比べて優れているかどうかはわかりません。配列は、デバッグビルドでパフォーマンス上の不利益を被ります(ただし、安全ではなく、安全でないポインターでは不可能なメモリ管理が改善されています)。そして、最適化されたリリースビルドでは、パフォーマンスは問題ありません。 – Rob

答えて

2

Performing Loop Iterations Concurrentlyに記載されているように、各ブロックがいくつかのバックグラウンドキューにディスパッチされるオーバーヘッドがあります。だから、あなたの配列を "跨ぐ"ことができ、それぞれの反復処理で複数のデータポイントを処理することができます。

また、Swift 3以降のconcurrentPerformと呼ばれるdispatch_applyは、ループを並列に実行するように設計されており、特定のデバイスのコア用に最適化されています。ストライドと組み合わせることで、あなたはいくつかのパフォーマンス上の利点を達成する必要があります

DispatchQueue.global(qos: .userInitiated).async { 
    let stride = 100 
    DispatchQueue.concurrentPerform(iterations: particles.count/stride) { iteration in 
     let start = iteration * stride 
     let end = min(start + stride, particles.count) 
     for i in start ..< end { 
      particles[i].update() 
      block[i] = particles[i].data//Copy the raw data into a thead safe format 
      queue.async { 
       let x1 = blocky[i].p1.x; let y1 = blocky[i].p1.y 
       let x2 = blocky[i].p2.x; let y2 = blocky[i].p2.x 

       let w = blocky[i].size * rectScale 
       let w2 = blocky[i].size * rectScale 

       let dy = y2 - y1; let dx = x2 - x1 
       let length = hypot(dy, dx) 
       let calcx = -dy/length 
       let calcy = dx/length 
       let calcx1 = calcx * w 
       let calcy1 = calcy * w 
       let calcx2 = calcx * w2 
       let calcy2 = calcy * w2 

       let writeIndex = i * 8 
       oblocky[writeIndex] = x1 + calcx1 
       oblocky[writeIndex+1] = y1 + calcy1 

       oblocky[writeIndex+2] = x1 - calcx1 
       oblocky[writeIndex+3] = y1 - calcy1 

       oblocky[writeIndex+4] = x2 + calcx2 
       oblocky[writeIndex+5] = y2 + calcy2 

       oblocky[writeIndex+6] = x2 - calcx2 
       oblocky[writeIndex+7] = y2 - calcy2 
      } 
     } 
    } 
} 

あなたは異なるstride値を試してみるとどのようにパフォーマンスの変化を確認する必要があります。

このコードは実行できません(サンプルデータはありません。Datasなどの定義はありません)。問題が発生した場合はお詫びします。しかし、ここでコードに集中するのではなく、並行ループを実行するためにconcurrentPerformを使用するという広範な問題に焦点を当ててください。スレッド化オーバーヘッドがより大きな利点を上回らないように各スレッドで十分な作業を確保するためには、スレッドを並列に実行する

詳細については、https://stackoverflow.com/a/22850936/1271826を参照してください。

2

あなたの期待は間違っている可能性があります。あなたの目標はメインスレッドを解放することでした。 そのは今速いです:メインスレッド!

しかし、バックグラウンドスレッドのasyncは、「これを実行してください」という意味です。「中止して他のコードを途中で実行できるようにしてください」という意味ではありません。すべて。あなたのコードにはqosの指定がありません。のようなものではありません。には特別な注意が必要です。

関連する問題