GCD的使用

简介

GCD为Grand Central Dispatch的缩写,是Apple开发的一个多核编程的较新的解决方法。

主要功能简介

  1. 调度队列
    所有的调度队列都是先进先出队列,因此,队列中的任务的开始的顺序和添加到队列中的顺序相同。GCD自动的为我们提供了一些调度队列,我们也可以创建新的用于具体的目的。
    下面列出几种可用的调度队列类型以及如何使用。
  2. 调度资源
    它是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block放入一个调度队列的执行例程中。
  3. 调度组
    允许将多任务分组来方便后来加入执行。任务能作为一个组中的一个成员被加到队列中,客户端能用这个组对象来等待直到这个组中的所有任务完成。
  4. 调度信号量
    允许客户端并行发布一定数量的任务。

用法简介

dispatch_queue

1.声明一个队列:

dispatch_queue_t myQueue = dispatch_queue_create("queueName", NULL);

其中,第一个参数是标识队列的,第二个参数是用来定义队列的参数。
2.执行一个队列:

dispatch_async(myQueue, ^{ [self doSomething]; });

其中,首先传入之前创建的队列,然后提供由队列运行的代码块。
3.暂停一个队列:

dispatch_suspend(myQueye);

如果暂停一个队列不要忘记恢复。暂停和恢复的操作和内存管理中的retain和release类似。调用dispatch_suspend会增加暂停计数,而dispatch_resume则会减少。队列只有在暂停计数变成零的情况下才开始运行。
4.恢复一个队列:

dispatch_resume(myQueue);

5.从队列中在主线程运行代码:

dispatch_sync(dispatch_get_main_queue(), ^{ 
    [self dismissLoginWindow]; }
);

有些操作无法再异步队列中执行,只能在主线程中执行,例如:UI绘图和关于NSNotificationCenter的操作

dispatch_group

如果想在dispatch_queue中所有的任务执行完成后在做某种操作,在串行队列中,可以把该操作放到最后一个任务执行完成后继续,但是在并行队列中怎么做呢。这就有dispatch_group 成组操作。比如:

dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next",DISPATCH_QUEUE_CONCURRENT); 
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ 
  NSLog(@"dispatch-1"); 
});
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ 
  NSLog(@"dspatch-2"); 
}); 
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){ 
  NSLog(@"end"); 
});

上面的 log1 和log2输出顺序不定,因为是在并行队列上执行,当并行队列全部执行完成后,最后到main队列上执行一个操作,保证“end”是最后输出。 另外,这里也可以不用创建自己的并行队列,用全局的global,那个也是个并行队列. dispatch_get_gloable_queue(0,0);

dispatch_barrier_async

先看段代码

dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT); 
dispatch_async(concurrentQueue, ^(){ 
  NSLog(@"dispatch-1"); 
}); 
dispatch_async(concurrentQueue, ^(){ 
  NSLog(@"dispatch-2"); 
}); 
dispatch_barrier_async(concurrentQueue, ^(){
  NSLog(@"dispatch-barrier"); 
}); 
dispatch_async(concurrentQueue, ^(){ 
  NSLog(@"dispatch-3");
}); 
dispatch_async(concurrentQueue, ^(){ 
  NSLog(@"dispatch-4"); 
}); 

dispatch_barrier_async 作用是在并行队列中,等待前面两个操作并行操作完成,这里是并行输出
dispatch-1,dispatch-2
然后执行
dispatch_barrier_async中的操作,(现在就只会执行这一个操作)执行完成后,即输出
"dispatch-barrier,最后该并行队列恢复原有执行状态,继续并行执行
dispatch-3,dispatch-4

dispatch_sync和dispatch_async

dispatch_sync():同步添加操作,他是等待添加进队列里面的操作完成之后再继续执行。
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT); 
NSLog(@"1"); 
dispatch_sync(concurrentQueue, ^(){ 
    NSLog(@"2"); [NSThread sleepForTimeInterval:10];
    NSLog(@"3"); 
});
 NSLog(@"4");

输出 :
11:36:25.313 GCDSeTest[544:303] 1
11:36:25.313 GCDSeTest[544:303] 2
11:36:30.313 GCDSeTest[544:303] 3//模拟长时间操作
11:36:30.314 GCDSeTest[544:303] 4

dispatch_async ,异步添加进任务队列,它不会做任何等待:
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT); 
NSLog(@"1"); 
dispatch_async(concurrentQueue, ^(){ 
    NSLog(@"2");
 [NSThread sleepForTimeInterval:5]; 
    NSLog(@"3"); }); 
NSLog(@"4");

输出:
** 11:42:43.820 GCDSeTest[568:303] 1**
** 11:42:43.820 GCDSeTest[568:303] 4**
** 11:42:43.820 GCDSeTest[568:1003] 2**
** 11:42:48.821 GCDSeTest[568:1003] 3//模拟长时间操作时间**

dispatch_apply

dispathc_apply 是dispatch_sync 和dispatch_group的关联API.它以指定的次数将指定的Block加入到指定的队列中。并等待队列中操作全部完成.

NSArray *array = [NSArray arrayWithObjects:
                  @"/Users/chentao/Desktop/copy_res/gelato.ds", 
                  @"/Users/chentao/Desktop/copy_res/jason.ds", 
                  @"/Users/chentao/Desktop/copy_res/jikejunyi.ds", 
                  @"/Users/chentao/Desktop/copy_res/molly.ds", 
                  @"/Users/chentao/Desktop/copy_res/zhangdachuan.ds", nil];
NSString *copyDes = @"/Users/chentao/Desktop/copy_des"; 
NSFileManager *fileManager = [NSFileManager defaultManager]; 
dispatch_async(dispatch_get_global_queue(0, 0), ^(){ 
    dispatch_apply([array count], dispatch_get_global_queue(0, 0), ^(size_t index){ 
    NSLog(@"copy-%ld", index); 
    NSString *sourcePath = [array objectAtIndex:index]; 
    NSString *desPath = [NSString stringWithFormat:@"%@/%@", copyDes, [sourcePath lastPathComponent]]; 
    [fileManager copyItemAtPath:sourcePath toPath:desPath error:nil]; 
}); 
  NSLog(@"done"); 
});

输出 copy-index 顺序不确定,因为它是并行执行的(dispatch_get_global_queue是并行队列),但是done是在以上拷贝操作完成后才会执行,因此,它一般都是放在dispatch_async里面(异步)。实际上,这里 dispatch_apply如果换成串行队列上,则会依次输出index,但这样违背了我们想并行提高执行效率的初衷。

dispatch_semaphore

dispatch_semaphore 信号量基于计数器的一种多线程同步机制。在多个线程访问共有资源时候,会因为多线程的特性而引发数据出错的问题。

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [NSMutableArrayarray];
for (int index = 0; index < 100000; index++) {
    dispatch_async(queue, ^(){
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//
        NSLog(@"addd :%d", index);
        [array addObject:[NSNumber numberWithInt:index]];
        dispatch_semaphore_signal(semaphore);
    });
}

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 如果semaphore计数大于等于1.计数-1,返回,程序继续运行。如果计数为0,则等待。这里设置的等待时间是一直等待。dispatch_semaphore_signal(semaphore);计数+1.在这两句代码中间的执行代码,每次只会允许一个线程进入,这样就有效的保证了在多线程环境下,只能有一个线程进入。

你可能感兴趣的:(GCD的使用)