GCD 的基本使用

要了解GCD的使用首先我们需要去了解 进程、线程 以及二者之间的关系,同时也需要去知道多线程的一些特点

一、 进程:

1.进程是一个具有一定独立功能的程序关于某次数据集合的一次运行活动,它是操作系统分配资源的基本单元.
2.进程是指在系统中正在运行的一个应用程序,就是一段程序的执行过程,我们可以理解为手机上的一个app.
3.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内,拥有独立运行所需的全部资源

二、 线程

1.程序执行流的最小单元,线程是进程中的一个实体.
2.一个进程要想执行任务,必须至少有一条线程.应用程序启动的时候,系统会默认开启一条线程,也就是主线程

三、 进程和线程的关系

1.线程是进程的执行单元,进程的所有任务都在线程中执行
2.线程是 CPU 分配资源和调度的最小单位
3.一个程序可以对应多个进程(多进程),一个进程中可有多个线程,但至少要有一条线程
4.同一个进程内的线程共享进程资源

四、 多线程

1.同一时间,CPU只能处理1条线程,只有1条线程在执行。多线程并发执行,其实是CPU快速地在多条线程之间调度(切换)。如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
2.如果线程非常非常多,CPU会在N多线程之间调度,消耗大量的CPU资源,每条线程被调度执行的频次会降低(线程的执行效率降低)

3.多线程的优点:

能适当提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)

4.多线程的缺点:

开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享

下面直接上代码吧。。。。

//同步任务 串行队列
    NSLog(@"\n\n同步任务");
    dispatch_queue_t queue = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
        dispatch_sync(queue, ^{
            NSLog(@"同步任务 %@", [NSThread currentThread]);
    });
    
    //异步任务  串行队列
    NSLog(@"\n\n异步任务");
    dispatch_queue_t queue1 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue1, ^{
        NSLog(@"异步任务 %@", [NSThread currentThread]);
    });
    
    //串行队列(同步串行)
    NSLog(@"\n\n串行队列");
    dispatch_queue_t queue33 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_sync(queue33, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
        }
    });

    dispatch_sync(queue33, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:2];
        }
    });
//串行队列(异步串行)//开启了新的线程
    NSLog(@"\n\n串行队列");
    dispatch_queue_t queue3 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue3, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
        }
    });

    dispatch_async(queue3, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"串行队列任务2_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:2];
        }
    });

    //并发队列(异步)
    NSLog(@"\n\n并发队列");

    dispatch_queue_t queue4 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue4, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"异步并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
        }
    });

    dispatch_async(queue4, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"异步并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:2];
        }
    });
    
    /**结果
     * 异步并发队列任务1_i:0 <NSThread: 0x6000017fc640>{number = 6, name = (null)}
     * 异步并发队列任务2_i:0 <NSThread: 0x6000017f09c0>{number = 5, name = (null)}
     * 异步并发队列任务1_i:1 <NSThread: 0x6000017fc640>{number = 6, name = (null)}
     * 异步并发队列任务2_i:1 <NSThread: 0x6000017f09c0>{number = 5, name = (null)}
     * 异步并发队列任务1_i:2 <NSThread: 0x6000017fc640>{number = 6, name = (null)}
     * 异步并发队列任务1_i:3 <NSThread: 0x6000017fc640>{number = 6, name = (null)}
     * 异步并发队列任务2_i:2 <NSThread: 0x6000017f09c0>{number = 5, name = (null)}
     * 异步并发队列任务1_i:4 <NSThread: 0x6000017fc640>{number = 6, name = (null)}
     * 异步并发队列任务2_i:3 <NSThread: 0x6000017f09c0>{number = 5, name = (null)}
     * 异步并发队列任务2_i:4 <NSThread: 0x6000017f09c0>{number = 5, name = (null)}
     */
    
    //并发队列(同步)
    
    NSLog(@"\n\n并发队列");

    dispatch_queue_t queue44 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_sync(queue44, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
        }
    });

    dispatch_sync(queue44, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:2];
        }
    });
    
    /**结果
     * 同步并发队列任务1_i:0 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务1_i:1 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务1_i:2 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务1_i:3 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务1_i:4 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务2_i:0 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务2_i:1 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务2_i:2 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务2_i:3 <NSThread: 0x60000159c100>{number = 1, name = main}
     * 同步并发队列任务2_i:4 <NSThread: 0x60000159c100>{number = 1, name = main}
    */

    //执行完之前的任务再执行后面的任务:
    
    NSLog(@"\n\n执行完之前的任务再执行后面的任务");
    dispatch_queue_t queue5 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue5, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
        }
    });
    //此时的queue 不能是全局的并发队列
    //dispatch_barrier_async 前面的任务先执行,后面的任务恢复原本规则执行
    dispatch_barrier_async(queue5, ^{
        NSLog(@"并发队列任务4");
    });

    dispatch_async(queue5, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:2];
        }
    });

    dispatch_async(queue5, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"并发队列任务3_i:%ld %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        }
    });
    /**结果
     * 异步并发队列任务1_i:0 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务1_i:1 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务1_i:2 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务1_i:3 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务1_i:4 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务3
     * 异步并发队列任务2_i:0 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务3_i:0 <NSThread: 0x6000025d0700>{number = 3, name = (null)}
     * 异步并发队列任务2_i:1 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务3_i:1 <NSThread: 0x6000025d0700>{number = 3, name = (null)}
     * 异步并发队列任务2_i:2 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务3_i:2 <NSThread: 0x6000025d0700>{number = 3, name = (null)}
     * 异步并发队列任务2_i:3 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务2_i:4 <NSThread: 0x60000258a000>{number = 5, name = (null)}
     * 异步并发队列任务3_i:3 <NSThread: 0x6000025d0700>{number = 3, name = (null)}
     * 异步并发队列任务3_i:4 <NSThread: 0x6000025d0700>{number = 3, name = (null)}
     */

    //使用主线程
    NSLog(@"\n\n使用主线程");
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(mainQueue, ^{
        NSLog(@"使用主线程  %@", [NSThread currentThread]);
    });

    //全局并发线程,用法和并发队列一致:
    NSLog(@"\n\n全局并发线程");
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        NSLog(@"全局并发线程  %@", [NSThread currentThread]);
    });
    
    //倒计时的实现
    /**
     * 1、获取主线程
     * 2、dispatch_time_t 设置延迟时间  第一个参数 默认 DISPATCH_TIME_NOW   第二个参数设置的是延迟的具体时间  单位纳秒 NSEC_PER_SEC  单位秒
     * 3、dispatch_after  是延迟时间之后的 任务块代码(实现延迟执行时需要)参数一是 dispatch_time_t  参数二是  主线程
     * 4、创建调度资源
     * 5、dispatch_source_set_timer  计时器的方法实现{
                      1、参数一:调度资源
     *                2、参数二:任务延迟时间即任务开始执行时间
     *                3、参数三:时间间隔
     *                4、参数四:余度  纳秒的回旋余地
     *     }
     * 注:调度资源  dispatch_source 不能为成员变量
     */
    
    double delayInSeconds = 2.0;
    dispatch_queue_t mainQueue2 = dispatch_get_main_queue();
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));//多久之后开始执行,时间是

//    dispatch_after(popTime, mainQueue, ^{
//        NSLog(@"延时执行的2秒 %@", [NSThread currentThread]);
//    });

    self.sourceTime = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, mainQueue2);
    dispatch_source_set_timer(self.sourceTime, popTime, (int64_t)(5 * NSEC_PER_SEC), 0);
    dispatch_source_set_event_handler(self.sourceTime, ^{
        NSLog(@"计时器 %@", [NSThread currentThread]);
    });
    dispatch_resume(self.sourceTime);
   
    //dispatch_group_t调度
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        sleep(8);
        NSLog(@"1111 %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"2222 %@", [NSThread currentThread]);
    });
    //当group上的任务都执行完成了调用
    dispatch_group_notify(group, queue, ^{
        NSLog(@"3333 %@", [NSThread currentThread]);
    });
    //当group上的任务都执行完了调用或者时间已经超过了设定的5秒调用
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
        NSLog(@"dispatch_group_wait 结束 %@", [NSThread currentThread]);
    });
    
    //使用 dispatch_group_enter 和 dispatch_group_leave 来处理异步线程的同步问题,这两个方法必须是要成对出现的,当 dispatch_group_leave 完成就回回调 dispatch_group_notify ,使用的时候可以比较灵活。

    dispatch_group_t group2 = dispatch_group_create();
    dispatch_group_enter(group2);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(3);
        NSLog(@"任务一完成 %@", [NSThread currentThread]);
        dispatch_group_leave(group2);
    });
    dispatch_group_enter(group2);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任务二完成 %@", [NSThread currentThread]);
        sleep(5);
        NSLog(@"任务三完成 %@", [NSThread currentThread]);
        dispatch_group_leave(group2);
    });
    dispatch_group_notify(group2, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任务完成 %@", [NSThread currentThread]);
    });
    
    /**结果
     * 任务二完成 <NSThread: 0x60000043c180>{number = 7, name = (null)}
     * 任务一完成 <NSThread: 0x600000465400>{number = 6, name = (null)}
     * 任务三完成 <NSThread: 0x60000043c180>{number = 7, name = (null)}
     * 任务完成 <NSThread: 0x60000043c180>{number = 7, name = (null)}
     */

注:只有异步线程才具备开启新线程的能力(并不一定开启新线程),同步是不能开启新线程

串行队列(Serial Dispatch Queue):
同一时间内,队列中只能执行一个任务,只有当前的任务执行完成之后,才能执行下一个任务。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)。主队列是主线程上的一个串行队列,是系统自动为我们创建的
并发队列(Concurrent Dispatch Queue):
同时允许多个任务并发执行。(可以开启多个线程,并且同时执行任务)。并发队列的并发功能只有在异步(dispatch_async)函数下才有效

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

推荐阅读更多精彩内容