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);</code></pre>

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.在这两句代码中间的执行代码,每次只会允许一个线程进入,这样就有效的保证了在多线程环境下,只能有一个线程进入。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容