GCD编程-控制线程最大并发量之信号量
NSOperationQueue
对象有一个属性 maxConcurrentOperationCount
,可以设置当前队列任务同时并发的最大个数,也就是同时执行任务的最大个数。比如我们下载很多电影,每个下载中的电影都是一个下载任务,如果设置maxConcurrentOperationCount=5
,则表示当前最大只能同时下载5部电影。
GCD是一套C语言的API,所以没有什么属性控制最大并发量。如果我们用的是GCD编程,需要现实这样的需求应该怎么办?那可以用dispatch_semaphore_t(信号量)
来实现。
什么是信号量呢?百科是这么说的:
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。
也就是说,信号量其实就是一个整数值,同时我们可以通过代码来控制器当前整数值。打个比方再来解释下信号量,如果一个停车场有10个车位,同时来了20辆车怎么办,最终只能有10辆汽车有车位,我们把车位个数10看做一个整数,就是信号量的值N等于10,当有一辆车进来,这当前车位数是N = N-1,依次类推,直到为0为止,其他车只能等待。当有其他车离开时,车位个数就为N=N+1,这时又可以有其他一辆车进来了。
那么我们用代码怎么实现呢?
//定义一个信号量,初始化为10
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
//同时执行100个任务
for (int i = 0; i < 100; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//当前信号量-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务%d执行",i+1);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kUrlString]];
dispatch_async(dispatch_get_main_queue(), ^{
//TODO:刷新界面
});
//当前信号量+1
dispatch_semaphore_signal(semaphore);
});
}
代码就这么多,就可以实现和NSOperationQueue的效果,很简单吧。我简单解释下代码:开始初始化一个信号量,默认为10,然后同时执行100个任务,所以每次最大并发是10。dispatch_semaphore_wait
表示是当前的信号量减去1,因为已经启动一个任务,所以通过这个方法来修改信号量的值。同样,当当前任务执行完后,要释放信号量,使当前信号量加1,所以用dispatch_semaphore_signal
方法即可。