2016-08-07 28 views
2

私はこの方法IOSスレッドプール

-(void)addObjectToProcess(NSObject*)object; 

を持っていると私は、この方法は、並列に4つのオブジェクトまで処理できるキューを処理するためにオブジェクトを追加します。

私は自分のdispatch_queueを作成し、

_concurrentQueue = dispatch_queue_create([queue_id UTF8String],DISPATCH_QUEUE_CONCURRENT); 
_processSema = dispatch_semaphore_create(4); 

をsemhphoreとメソッドの実装がありました:

-(void)addObjectToProcess(NSObject*)object { 
    dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER); 
    __weak MyViewController* weakSelf = self; 

    dispatch_async(self.concurrentQueue, ^{ 
     // PROCESS........... 
     // .................. 
     dispatch_semaphore_signal(self.processSema); 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // call delegate from UI thread 
     }); 
    }); 
    } 

発信者が時々セマフォ障壁の原因をブロックされるようです。

私がここで作成しようとしているものを実装するための他の/簡単なオプションはありますか?

おかげ

+1

ところで、セマフォの問題以外にも、コードには2つの問題があります。第一に、 'weakSelf'はあなたが望むものを達成するつもりはありません。なぜならクロージャーの中にリファレンスselfがあり、View Controllerを強く参照しているからです。だから、弱い参照は無用です。第2に、closure内の 'self'参照を' weakSelf'で置き換えるだけでは不十分です。これは競合条件を導入するためです。そのクロージャ内に新しい 'strongSelf'参照を作成する必要があります(' self'を参照するのではなく、 'weakSelf'への新しい強い参照を作成するだけです)。 – Rob

答えて

3

問題は、あなたが(おそらくメインスレッド)にaddObjectToProcessと呼ばれるものは何でもスレッド上dispatch_semaphore_waitを呼んでいるということです。したがって、すでに4つのタスクを実行している場合、この5番目のプロセスをスケジュールすると、メインスレッドで待機します。

セマフォの待機をself.concurrentQueueにディスパッチされたブロックに移動したいのですが、これは "PROCESS"タスクを一度に4つに制限しますが、別のワーカースレッドこれらのバックログされたディスパッチされたタスクのそれぞれについて、それらのワーカースレッドの有限数が存在する。そしてそれらを使い果たすと、他のプロセスに悪影響を与える可能性があります。

これに対処する1つの方法は、並行処理キューに加えてシリアルスケジューリングキューを作成し、このスケジューリングタスク全体をこのスケジューリングキューに非同期にディスパッチすることです。したがって、メインスレッドをブロックすることも、バックログされたタスクにワーカースレッドを使用することもなく、プロセスキューで最大の同時実行性を享受できます。例えば:

@property (nonatomic, strong) dispatch_queue_t schedulingQueue; 

そして

self.schedulingQueue = dispatch_queue_create("com.domain.scheduler", 0); 

そして

- (void)addObjectToProcess(NSObject*)object { 
    dispatch_async(self.schedulingQueue, ^{ 
     dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER); 
     typeof(self) __weak weakSelf = self; 

     dispatch_async(self.concurrentQueue, ^{ 
      // PROCESS........... 
      // .................. 
      typeof(self) __strong strongSelf = weakSelf; 
      if (strongSelf) { 
       dispatch_semaphore_signal(strongSelf.processSema); 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        // call delegate from UI thread 
       }); 
      } 
     }); 
    }); 
} 

もう一つの良いアプローチは、( "プロセス" が同期している場合は特に)を制御maxConcurrentOperationCountを有するNSOperationQueueを使用することですあなたの並行性の程度。その後、

self.processQueue = [[NSOperationQueue alloc] init]; 
self.processQueue.maxConcurrentOperationCount = 4; 

そして:

@property (nonatomic, strong) NSOperationQueue *processQueue; 

そして、それを初期化します。たとえば

- (void)addObjectToProcess(NSObject*)object { 
    [self.processQueue addOperationWithBlock:^{ 
     // PROCESS........... 
     // .................. 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // call delegate from UI thread 
     }); 
    }]; 
} 

唯一のトリックは、 "プロセス" は、それ自体が、非同期である場合です。その場合は、addOperationWithBlockを使用するだけではなく、独自のカスタム非同期NSOperationサブクラスを作成してから、をNSOperationQueueに使用する必要があります。非同期NSOperationサブクラスを記述するのは難しいことではありませんが、それに関連する詳細はほとんどありません。 「同時処理プログラミングガイド」のConfiguring Operations for Concurrent Executionを参照してください。

関連する問題