iOS线程之GCD初探

简述:
说道线程,离不开并行和串行,所谓并行,就是100赛跑,每个赛道就是一个线程,每个线程之间互不影响,同时都可以运行事件,就是10个赛道都可以有运动员跑步了,谁跑的慢或者跑的快,都不影响其他的人。串行就不一样了,串行是1个赛道10个运动员再跑接力赛,第一个跑到终点第二个在接着跑,依次类推,前边的不走,后边的也走不了的,所以串行上面的事件是一个一个运行的,同时只能是一个人再跑。

在iOS或者OS里面,一般用GCD就能处理较多的事务,下面就谈一下GCD的用法。

什么是GCD?

全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
纯C语言,提供了非常多强大的函数

methodList info


//获取主线程 就是更新UI的线程
dispatch_queue_t dispatch_get_main_queue(void);

 //获取全局队列
dispatch_queue_t dispatch_get_global_queue( long identifier, unsigned long flags);

//创建一个队列 名字是label 属性可以写为NULL  
dispatch_queue_t dispatch_queue_create( const char *label dispatch_queue_attr_t attr);
dispatch_release(queue)//释放队列

//获取代码现在运行的queue
dispatch_queue_t dispatch_get_current_queue( void);

 //获取队列的名字
const char * dispatch_queue_get_label(dispatch_queue_t queue);

//异步把代码块block交给queue队列中处理
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

// 同步将block加入到queue中并且执行。
void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);

 //block 在指定时间在queue中执行
void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

 
//几个调度事件同事加入到queue中去,最好是全局队列才行。
void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t));

// block 是否执行过
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
 
//在分组group中的queue队列执行block
void dispatch_group_async( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

//创建线程分组
dispatch_group_t dispatch_group_create( void);

 //分组的计数+1
void dispatch_group_enter( dispatch_group_t group);

//分组计数 -1
void dispatch_group_leave( dispatch_group_t group);

// 当分组中的事务处理完了执行block
void dispatch_group_notify( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

//等待timeout时间后执行 group中的事务
long dispatch_group_wait( dispatch_group_t group, dispatch_time_t timeout);

 //并行状态下 queue前面的并行事务处理完成了在执行block,然后执行下边的并行代码
//比如 ABCDEF D事务等到ABC都完成了在执行EF事务的
void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);

实战演练全局队列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
        //异步执行
        dispatch_sync(dispatch_get_main_queue(), ^{
            //这里面更新UI
        });
    });
    dispatch_sync(queue, ^{
       //同步执行
    });

自定义队列

dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_SERIAL);
    //
//#define DISPATCH_QUEUE_SERIAL   同步队列
//#define DISPATCH_QUEUE_CONCURRENT 异步队列
    dispatch_async(queue, ^{
        NSLog(@"下载图片1=====%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"下载图片2=====%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"下载图片3=====%@",[NSThread currentThread]);
    });
    NSLog(@"main:%@",[NSThread mainThread]);
当queue属性为 DISPATCH_QUEUE_CONCURRENT输出:
**2016-03-28 16:53:25.848 GCD_Demo[12338:347984] ****下载图片****3=====<NSThread: 0x7fabda100250>{number = 4, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347982] ****下载图片****2=====<NSThread: 0x7fabda2008a0>{number = 3, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347937] main:<NSThread: 0x7fabd8c04ee0>{number = 1, name = main}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347981] ****下载图片****1=====<NSThread: 0x7fabd8c0a010>{number = 2, name = (null)}** 线程达到了4个
当queue属性为DISPATCH_QUEUE_SERIAL输出:
**2016-03-28 16:46:54.501 GCD_Demo[12272:344348] main:<NSThread: 0x7fd379704cf0>{number = 1, name = main}**
**2016-03-28 16:46:54.501 GCD_Demo[12272:344382] ****下载图片****1=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下载图片****2=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下载图片****3=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
线程只有2个

多个异步线程问题

# 当ABC 3个异步线程,要求前两个个执行完再去执行后面的三个的时候例子:
     dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"queue1 begin");
        sleep(2);
        NSLog(@"queue1 end");
    });
    dispatch_async(queue, ^{
        NSLog(@"queue2 begin");
        sleep(2);
        NSLog(@"queue2 end");
    });
    dispatch_barrier_sync(queue, ^{
        NSLog(@"main:%@",[NSThread mainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"queue3 begin");
        sleep(2);
        NSLog(@"queue3 end");
    });
输出:

**2016-03-28 17:01:01.319 GCD_Demo[12463:353702] queue2 begin**
**2016-03-28 17:01:01.319 GCD_Demo[12463:353703] queue1 begin**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353703] queue1 end**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353702] queue2 end**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353657] main:<NSThread: 0x7f97ea604bf0>{number = 1, name = main}**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353702] queue3 begin**
**2016-03-28 17:01:05.330 GCD_Demo[12463:353702] queue3 end**

线程分组

# 当多个任务同时进行的时候,也可以用group,ABCD任务进行完成的时候,最后在执行task。
 

  dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task1 begin");
        sleep(2);
        NSLog(@"task1 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task2 begin");
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"=================");
    });
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task3 begin");
        sleep(2);
        NSLog(@"task3 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task4 begin");
        sleep(2);
        NSLog(@"task4 end");
    });
输出:
**2016-03-28 17:08:45.002 GCD_Demo[12557:357162] task1 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357164] task4 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357161] task2 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357163] task3 begin**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357162] task1 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357163] task3 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357164] task4 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357161] task2 end**
**2016-03-28 17:08:47.006 GCD_Demo[12557:357161] =================**
一个组内的所有任务都进行完了才会执行task的函数。


# 分组多任务等待 ABCDEF ,ABCD执行5秒,5秒之后就执行EF任务,不管ABCD是否成功。

    dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task1 begin");
        sleep(2);
        NSLog(@"task1 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task2 begin");
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"=================");
    });
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task3 begin");
        sleep(6);
        NSLog(@"task3 end");
    });
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)));
    NSLog(@"all end");
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task4 begin");
        sleep(2);
        NSLog(@"task4 end");
    });
输出:
# 代码执行到wait的时候会等待5秒之后再执行wait下边的代码,和sleep有点相似。
**2016-03-28 17:26:31.335 GCD_Demo[12745:366983] task3 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366978] task1 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366979] task2 begin**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366978] task1 end**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366979] task2 end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366894] all end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366979] task4 begin**
**2016-03-28 17:26:37.340 GCD_Demo[12745:366983] task3 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366979] task4 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366983] =================**

同时处理多数据不管顺序

          dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
          /*! dispatch_apply函数说明
           10      *
           11      *  @brief  dispatch_apply函数是dispatch_sync函数和Dispatch Group的关联API
           12      *         该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等到全部的处理执行结束
           13      *
           14      *  @param 10    指定重复次数  指定10次
           15      *  @param queue 追加对象的Dispatch Queue
           16      *  @param index 带有参数的Block, index的作用是为了按执行的顺序区分各个Block
           17      *
           18      */
          dispatch_apply(10, queue, ^(size_t index) {
                  NSLog(@"%d", index);
              
              });
          NSLog(@"done");
输出:
# 这个和上边讲的分组类似,多事务处理,处理结束后再执行代码。
# 这个是同步的,代码按顺序执行,分组的是异步执行的block
**2016-03-28 17:36:35.698 GCD_Demo[12857:372458] 1**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372463] 5**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372429] 4**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372464] 6**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372465] 7**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372462] 2**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372457] 0**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372461] 3**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372458] 8**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] 9**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] done**
    

参考文章:Grand Central Dispatch (GCD) Reference
GCD提供的接口蛮多的,适用场景还是要熟练掌握,才能运用自如。
更多文章:www.fgyong.cn

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

推荐阅读更多精彩内容