我有这个方法
-(void)addObjectToProcess(NSObject*)object;
我希望这个方法将对象添加到进程队列,该队列可以并行处理多达4个对象。
我已经创建了自己的dispatch_queue和semhphore
_concurrentQueue = dispatch_queue_create([queue_id UTF8String],DISPATCH_QUEUE_CONCURRENT);
_processSema = dispatch_semaphore_create(4);
并且该方法的实现是:
-(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
});
});
}
似乎调用者有时会因信号量障碍而被阻止。
有没有其他/更容易的选择来实现我想在这里做的事情?
由于
答案 0 :(得分:3)
问题是你在dispatch_semaphore_wait
上调用的任何线程上调用addObjectToProcess
(可能是主线程)。因此,如果您已经运行了四个任务,那么当您安排第五个进程时,它将在主线程上等待。
但是,您不希望将等待信号量转移到发送到self.concurrentQueue
的块中,因为虽然这会将“PROCESS”任务成功约束为四个,但您将消耗这些积压调度任务中的每一个都有另一个工作线程,并且这些工作线程数量有限。当你耗尽这些时,你可能会对其他过程产生不利影响。
解决此问题的一种方法是创建除并发处理队列之外的串行调度队列,然后将此整个调度任务异步调度到此调度队列。因此,您可以享受进程队列中的最大并发性,同时既不会阻塞主线程也不会使用工作线程来执行积压任务。例如:
@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
});
}
});
});
}
另一个好的方法(特别是如果“PROCESS”是同步的)是使用NSOperationQueue
,maxConcurrentOperationCount
,它控制你的并发度。例如:
@property (nonatomic, strong) NSOperationQueue *processQueue;
并初始化它:
self.processQueue = [[NSOperationQueue alloc] init];
self.processQueue.maxConcurrentOperationCount = 4;
然后:
- (void)addObjectToProcess(NSObject*)object {
[self.processQueue addOperationWithBlock:^{
// PROCESS...........
// ..................
dispatch_async(dispatch_get_main_queue(), ^{
// call delegate from UI thread
});
}];
}
唯一的技巧是“PROCESS”本身是异步的。如果你这样做,那么你不能只使用addOperationWithBlock
,而是必须编写自己的自定义异步NSOperation
子类,然后使用addOperation
到NSOperationQueue
。编写异步NSOperation
子类并不难,但有一些与此相关的细节。请参阅并发编程指南中的Configuring Operations for Concurrent Execution。