IOS 线程池

IOS thread pool

我有这个方法

-(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
        });
    });
    }

似乎调用者有时会因为信号量障碍而被阻塞。

是否有任何 other/easier 选项来实现我在这里尝试做的事情?

谢谢

问题是您在调用 addObjectToProcess 的任何线程(大概是主线程)上调用 dispatch_semaphore_wait。因此,如果您已经有四个任务 运行,当您安排第五个进程时,它将在主线程上等待。

不过,您不只是想将等待信号量的任务移到分派给 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