我有这个方法
-(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
});
});
}
似乎调用者有时会因为信号量障碍而被阻塞。
还有其他/更简单的选择来实现我在这里尝试做的事情吗?
谢谢
问题是您在调用 addObjectToProcess
的任何线程(可能是主线程)上调用 dispatch_semaphore_wait
。因此,如果您已经有四个任务在运行,那么当您安排这第五个进程时,它将在主线程上等待。
不过,您不只是想将等待信号量移动到分派(dispatch)到 self.concurrentQueue
的 block 中,因为这样会成功地将“PROCESS”任务限制为四个时间,您将为这些积压的调度任务中的每一个消耗另一个工作线程,并且这些工作线程的数量是有限的。当你用尽这些时,你可能会对其他进程产生不利影响。
解决此问题的一种方法是在并发处理队列之外创建一个串行调度队列,然后将整个调度任务异步分派(dispatch)到该调度队列。因此,您可以享受进程队列的最大并发性,同时既不会阻塞主线程,也不会用完工作线程来处理积压的任务。例如:
@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”是同步的)是使用具有 maxConcurrentOperationCount
的 NSOperationQueue
,它可以为您控制并发程度。例如:
@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在并发编程指南中。
关于IOS线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38812161/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |