iOS多线程编程之GCD

文章资料来源《Objective-C高级编程》之GCD

GCD是一种异步执行任务的技术,对于编程层面上异步执行就意味着创建一个线程(操作系统能夠進行運算调度的最小單位,是进程中一个单一顺序的控制流--from wiki)去执行Task;GCD提供了两种队列和相关API使得开发者只需要关心该选择哪种队列去执行任务即可;

GCD的队列

  • serial queue 能够保证各个task在同一个线程中被执行并且执行顺序会严格的按照入队的顺序进行;
  • concurrent queue 各个task的执行互不影响,执行顺序上不确定,执行线程也不一定会相同;
dispatch_queue_create 创建队列

serial queue

  /*
 1>serial Queue:系统默认创建一个线程,队列中的任务是顺序执行
 2>创建多个serial queue 的执行是并发的没有顺序
 3>解决数据竞争问题:可以将任务放在serial queue中 保证任务按照顺序执行就能解决数据竞争
*/
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);

concurrent queue

 /*
  1 concurrent queue 添加到队列中的任务会并发执行,没有顺序性
 */
dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

非ARC下生成的队列还必须使用dispatch_release(Queue);来释放指定的队列

Main Dispatch Queue and Global Dispatch Queue

Main Dispatch Queue

  /*
  dispatch_get_main_queue
 (1)main queue 是一中serial queue,task是放在主线程的Runloop中执行的;
 (2)一些UI的更新操作需要放在主线程中,使用main queue是比较简单的
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();

global Dispatch Queue

 /*
   dispatch_get_global_queue
 (1)global queue 是一种concurrent queue,可以通过设置queue的priority指定执行的优先级;
 */
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

dispatch_set_target_queue

 /*
 dispatch_set_target_queue的第一个参数是指定要变更优先级的队列;指定与要使用优先级相同优先级的队列为第二个参数
 */
dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
dispatch_set_target_queue(serialqueue2, serialqueue1);
/*  

dispatch_after

/*
  延迟若干时间处理某一个Task,只是追加task到某一个队列,并不一定立即执行task
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
    NSLog(@"wait at least three seconds!!");
});

dispatch Group

dispatch group 的出现可以解决多个并发task执行后能收到通知再执行其他任务操作的需求;

  /*
  1; 如果使用 serial queue 所有的task执行完毕后在执行done task
  2:如果使用 concurrent queue 所有的task执行后没办法 执行行done task 就需要 dispatch_group
 */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//
dispatch_group_async(group, queue, ^{
    NSLog(@"blok1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok2");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok3");
});
dispatch_group_async(group, queue, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"blok4");
});
// 监听group 中的task 是否已经全部执行完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"done!!");
});
//   dispatch_group_wait会hold住当前线程直到所有task执行完毕
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"all finish!!!!");

多个网络请求执行操作完成在执行下一步操作的需求如何实现?

 // 多个网络请求完成后再做新的任务
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作1
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作2
        dispatch_group_leave(group);
    });

dispatch_barrier_async

多线程操作产生的一个问题就是数据资源的竞争,读写操作如何能保证线程安全性;dispatch_barrier_async提供了解决方案

 /*
   使用concurrent dispatch queue 和 dispatch barrier async 函数可实现高效率的数据库访问和文件读取
 */
dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"task1forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task2forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task3forReading!");
});
dispatch_barrier_async(queue, ^{
    // 此taskforWriting 会等到加入concurrentQueue中的task执行完毕后,执行taskforWriting,等到该taskforWriting执行完毕后在执行 concurrentQueue中的task
    NSLog(@"taskforWriting!");
});
dispatch_async(queue, ^{
    NSLog(@"task4forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task5forReading!");
});

dispatch_sync

/*
dispatch_sync 函数意味着等待;它要等待task执行完毕后再做返回
*/
//使用dispatch_sync 容易造成死锁
//在主线程中执行以下源代码会造成死锁
/*
  main_queue 是一个serialQueue ,使用dispatch_sync将task加入到mainqueue中task会等待mainqueue中的任务执行完成,而mainqueue又要等待task完成,由此造成了死锁;
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
    NSLog(@"hello dispatch_sync!");
});
//>2在主线程中执行以下源代码也会造成死锁
dispatch_async(main_queue, ^{
   dispatch_sync(main_queue, ^{
       NSLog(@"hello!!");
   });
});

dispatch_apply

  NSMutableArray* tempArr  = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
   // 1 按照指定的次数将指定的Block追加到指定的Dispatch_Queue中,并等待全部处理执行结束
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply([tempArr count], queue, ^(size_t index) {
        // 要做数据更新操作
        NSLog(@"%d",index);
    });
    NSLog(@"task done");
    /*
     1 对数组进行循环遍历的方法
       1》 for循环
       2》 block
       3》 dispatch_apply
      2 dispatch_apply 要等待结束,最好和 dispatch_async函数混合使用
     */

挂起队列和执行队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//挂起队列
dispatch_suspend(queue);
//恢复指定队列
dispatch_resume(queue);  

dispatch_Semaphore

 // 1  向数组中增加对象由于内存错误导致异常的概率会很高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray* mutable_arr =[NSMutableArray array];
for(int i = 0;i<100000;++i)
{
   dispatch_async(queue, ^{
       [mutable_arr addObject:[NSNumber numberWithInt:i]];
   });
}


// 2 使用dispatch_semaphore进行更细粒度的线程管理
dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
  生成Dispatch Semahpore
  dispatch_Semahpore 的计数初始值设定为“1”
  这样能保证访问NSMutableArray类对象的线程,同时只有1个
 */
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray* array =[NSMutableArray array];
for(int i = 0;i<10000;i++)
{
    dispatch_async(global_queue, ^{
        /*
         等待Dispatch Semaphore
         直到Dispatch Semphore的计数值达到大于等于1;
         */
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        /*
         由于dispatch Semaphore 的计数值达到大于等于1
         所以将Dispatch semaphore 的计数值减去1
         dispatch_semaphore_wait 函数执行返回
         执行到此 dispatch Semaphore的计数值恒为“0”
         */
        
        [array addObject:[NSNumber numberWithInt:i]];
        
        /*
         排他控制处理结束,所以通过dispatch_semaphore_signal函数 将
         Dispatch Semaphore的计数值加1
         如果有通过dispatch_semaphore_wait 函数 等待dispatch Semaphore 的计数值增加的线程 就由最先等待的线程执行
         */
        dispatch_semaphore_signal(semaphore);

    });
}

dispatch_once

保证应用程序中只执行一次指定处理的API

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

推荐阅读更多精彩内容

  • 1. GCD简介 iOS开发中多线程的API主要有pthread,NSThread,NSOperation和GCD...
    安东_Ace阅读 1,242评论 0 6
  • 本文的写作目的是为学习记录,同时分享给大家,希望大神能够对文中错误的理解进行指正。 如果文章内容涉及到其他已经发表...
    油菜小白阅读 673评论 0 2
  • 本篇博客共分以下几个模块来介绍GCD的相关内容: 多线程相关概念 多线程编程技术的优缺点比较? GCD中的三种队列...
    有梦想的老伯伯阅读 1,015评论 0 4
  • GCD(Grand Central Dispatch)是iOS多任务的核心,它可以让程序员不用直接参与到线程的创建...
    koce_zhao阅读 263评论 0 1
  • 去上海是清明前一周定下来的,虽然老公颇有微词,他认为我们应该选一个有山有水,慢节奏适合自驾的地方去度假。但扛...
    limingzhuo阅读 253评论 0 0