iOS多线程开发之离不开的GCD(上篇)

一、GCD基本概念

GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了?种新的方法来进?并发程序编写。从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程序将任务切分为多个单一任务,然后提交??作队列来并发的或者串?的执行。GCD是C实现,?NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分 并发任务会像NSOperationQueue那样基于系统负载来合适地并发进?,而串?行队列同一时间只执行单一任务,GCD的API很大程度上基于block。

GCD并发编程的主要好处归纳

  • GCD可用于多核的并行运算
  • GCD会自动利用更多的CPU内核(比如双核、四核)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

二、GCD如何实现

GCD主要由队列和任务两部分来实现,苹果官方对GCD是这样说明的:开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。Dispatch Queue是执行处理的等待队列,我们可以通过dispatch_async等API,在block语法中记述想要执行的处理并将其追加到Dispatch Queue中,Dispatch Queue是按照追加的顺序进行处理(先进先出FIFO)。

多线程执行过程就是把任务放在队列中去执行的过程。那么在这里我们首先回顾一下基本概念:

(一)进程/线程、任务/队列

(二)同步/异步、并发/并行

并发不一定等于并行

 (三)异步/同步任务 & 并行/串行队列的特点

综上所述,iOS多线程编程使用GCD的最优原则是能不在阻碍主线程(又叫作UI线程)的情况下,开启新的线程(子线程)去处理耗时的操作,以便有效提高程序的执行效率和资源利用率,但是同时开启多个子线程也会引发许多其他的问题,如资源竞争、死锁、内存损耗等,所以要注意,这篇文章只是介绍GCD的使用,因此可能产生的问题我将会在这个系列后续篇章做介绍。

GCD并发编程产生的作用归纳(考虑线程安全,不死锁的情况下效果):

  • 能开启新的线程(子线程)
  • 多个任务可以同时进行
  • 不会阻塞主线程(又叫作UI线程)影响UI事件

三、GCD如何使用

开发者要做的只是定义想执行的任务并追加到适当的队列(Dispatch Queue)中

1、创建队列(Dispatch Queue)

第一种:通过GCD的API的dispatch_queue_create函数生成Dispatch Queue

// 创建串行队列
dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);

// 创建并发队列
dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_CONCURRENT);

    另外需要注意的点是:虽然有ARC编译器自动管理内存这一优秀技术,但生成的Dispatch Queue必须由程序员主动释放。

// 释放
dispatch_release(exampleSerialDispatchQueue) 

// 持有
dispatch_retain(exampleSerialDispatchQueue) 

第二种:直接使用系统提供的标准Dispatch Queue :Main Dispatch Queue和Global Dispatch Queue

(1)Main Dispatch Queue:主线程中执行的Dispatch Queue,也就是Serial Dispatch Queue(串行队列),可以通过dispatch_get_main_queue()来获取。

dispatch_queue_t   mainDispatchQueue = dispath_get_main_queue();

(2)  Global Dispatch Queue: 全局并发队列(Concurrent Dispatch Queue),GCD默认提供了全局的并发队列,可以通过dispatch_get_global_queue()获取。

// 高优先级
dispatch_queue_t globalDispatchQueueHigh = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)  

// 默认优先级
dispatch_queue_t globalDispatchQueueDefault = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) 

// 低优先级
dispatch_queue_t globalDispatchQueueLow = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0)  

// 后台优先级
dispatch_queue_t globalDispatchQueueBackgroud = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_GACKGROUND,0)  

2、创建任务

// 同步执行任务创建方法
dispatch_sync(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);    // 这里放任务代码
});

// 异步执行任务创建方法
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);    // 这里放任务代码
});

四、队列任务组合

根据(二)中描述,GCD由队列和任务两部分组成,队列分为串行队列、并行队列、主队列,任务可分为同步和异步任务,这样可将队列与任务组合如下:

1、并行队列 & 异步执行

- (void) asyncConcurrentTask
{
    NSLog(@"asyncConcurrentTask---start");

    dispatch_queue_t queue= dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"Task1------%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2------%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3------%@",[NSThread currentThread]);
    });

    NSLog(@"asyncConcurrentTask---end");
}

打印结果:

2017-07-02 11:13:10.963 Test[6266:2853210] asyncConcurrentTask---start
2017-07-02 11:13:10.963 Test[6266:2853210] asyncConcurrentTask---end
2017-07-02 11:13:10.963 Test[6266:2854044] Task3------<NSThread: 0x60800007cdc0>{number = 5, name = (null)}
2017-07-02 11:13:10.963 Test[6266:2854059] Task2------<NSThread: 0x60800007d1c0>{number = 4, name = (null)}
2017-07-02 11:13:10.963 Test[6266:2854041] Task1------<NSThread: 0x600000074e80>{number = 3, name = (null)}

结论:

(1) 开启了新线程

(2) 任务之间不需要排队,且具有同时被执行的权利

2、并行队列 & 同步执行

- (void)syncConcurrentTask
{
    dispatch_queue_t queue = dispatch_queue_create("com.beck.wang.queue", DISPATCH_QUEUE_CONCURRENT);

   NSLog(@"syncConcurrentTask---start---");

   dispatch_sync(queue, ^{
        NSLog(@"Task1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task3---%@", [NSThread currentThread]);
    });

    NSLog(@"syncConcurrentTask---end---");
}

打印结果:

2017-07-02 11:25:04.725 Test[6385:2940867] syncConcurrentTask---start---
2017-07-02 11:25:04.725 Test[6385:2940867] Task1---<NSThread: 0x608000067540>{number = 1, name = main}
2017-07-02 11:25:04.726 Test[6385:2940867] Task2---<NSThread: 0x608000067540>{number = 1, name = main}
2017-07-02 11:25:04.726 Test[6385:2940867] Task3---<NSThread: 0x608000067540>{number = 1, name = main}
2017-07-02 11:25:04.726 Test[6385:2940867] syncConcurrentTask---end---

结论:

(1) 不开启了新线程

(2) 任务之间需要排队,按照追加顺序执行

3、串行队列 & 异步执行

- (void)asyncSerialTask
{
    dispatch_queue_t queue = dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"asyncSerialTask---start---");

    dispatch_async(queue, ^{
        NSLog(@"Task1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3---%@", [NSThread currentThread]);
    });
    NSLog(@"asyncSerialTask---end---");
}

打印结果:

2017-07-02 11:36:27.068 Test[6557:3008079] asyncSerialTask---start---
2017-07-02 11:36:27.068 Test[6557:3008079] asyncSerialTask---end---
2017-07-02 11:36:27.068 Test[6557:3008342] Task1---<NSThread: 0x600000071e00>{number = 3, name = (null)}
2017-07-02 11:36:27.069 Test[6557:3008342] Task2---<NSThread: 0x600000071e00>{number = 3, name = (null)}
2017-07-02 11:36:27.069 Test[6557:3008342] Task3---<NSThread: 0x600000071e00>{number = 3, name = (null)}

结论:

(1) 开启了新线程

(2) 任务之间需要排队,按照追加顺序执行

4、串行队列 & 同步执行

- (void)syncSerialTask
{
    dispatch_queue_t queue = dispatch_queue_create("com.beckwang.queue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"syncSerialTask---start---");

    dispatch_sync(queue, ^{
        NSLog(@"Task1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task3---%@", [NSThread currentThread]);
    });

    NSLog(@"syncSerialTask---end---");
}

打印结果:

2017-07-02 13:17:48.948 Test[7238:3192943] syncSerialTask---start---
2017-07-02 13:17:48.948 Test[7238:3192943] Task1---<NSThread: 0x600000076640>{number = 1, name = main}
2017-07-02 13:17:48.949 Test[7238:3192943] Task2---<NSThread: 0x600000076640>{number = 1, name = main}
2017-07-02 13:17:48.949 Test[7238:3192943] Task3---<NSThread: 0x600000076640>{number = 1, name = main}
2017-07-02 13:17:48.949 Test[7238:3192943] syncSerialTask---end---

结论:

(1) 不开启了新线程

(2) 任务之间需要排队,按照追加顺序执行

5、主队列 & 异步执行

- (void)asyncMainTask
{
    dispatch_queue_t queue = dispatch_get_main_queue();

    NSLog(@"asyncMainTask---start---");

    dispatch_async(queue, ^{
        NSLog(@"Task1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3---%@", [NSThread currentThread]);
    });

    NSLog(@"asyncMainTask---end---");
}

打印结果:

2017-07-02 13:19:36.828 Test[7272:3206224] asyncMainTask---start---
2017-07-02 13:19:36.828 Test[7272:3206224] asyncMainTask---end---
2017-07-02 13:19:36.834 Test[7272:3206224] Task1---<NSThread: 0x608000072480>{number = 1, name = main}
2017-07-02 13:19:36.834 Test[7272:3206224] Task2---<NSThread: 0x608000072480>{number = 1, name = main}
2017-07-02 13:19:36.834 Test[7272:3206224] Task3---<NSThread: 0x608000072480>{number = 1, name = main}

结论:

(1) 不开启了新线程

(2) 任务之间需要排队,按照追加顺序执行

6、主队列 & 同步执行

- (void)syncMainTask{

    dispatch_queue_t queue = dispatch_get_main_queue();

    NSLog(@"syncMainTask---start---");

    dispatch_sync(queue, ^{
        NSLog(@"Task1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"Task3---%@", [NSThread currentThread]);
    });

    NSLog(@"syncMainTask---end---");
}

打印结果:

2017-07-02 13:22:31.860 Test[7335:3230988] syncMainTask---start---

结论:

发生死锁,程序崩溃。

好了GCD系列的上篇就写到这里,我将在后续系列中详细介绍GCD的队列系列和用法,以及使用GCD可能造成的问题及解决方案,水平有限,有不对的地方还望批评指正!

时间: 2024-08-18 12:33:14

iOS多线程开发之离不开的GCD(上篇)的相关文章

iOS多线程开发小demo6 GCD

// DYFViewController.m // 623-07-GCD // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @property (weak, nonatomic) IBOutlet UIImageVi

iOS多线程开发——NSThread浅析

在IOS开发中,多线程的实现方式主要有三种,NSThread.NSOperation和GCD,我前面博客中对NSOperation和GCD有了较为详细的实现,可以参考<iOS多线程开发--NSOperation/NSOperationQueue浅析><iOS多线程开发--GCD的使用与多线程开发浅析>.以及对于多线程中的同步异步,并行串行等概念,我在<GCD实践--串行队列/并发队列与iOS多线程详解>中也有较为详细的讲解.为了学习的完整性,今天我们主要从代码层面来实现

IOS多线程开发

本文转载至 http://blog.csdn.net/davidsph/article/details/8171607 IOS的多线程,一般分为三种方式: 1,Thread;2, Cocoa operations;3, Grand Central Dispatch (GCD) (iOS4 才开始支持) 下面简单说明一下: 1:NSThread   创建方式主要有两种: [NSThread detachNewThreadSelector:@selector(myThreadMainMethod:)

iOS多线程开发——GCD的使用与多线程开发浅析(二)

对于iOS多线程开发,我们时刻处于学习之中,在看书中,看文档中,项目开发中,都可以去提高自己.最近刚看完了<Objective-C高级编程 iOS与OS X多线程和内存管理>这本书后,对多线程有了更为深入的理解,故在此做一个总结与记录.这本书我已经上传至网盘  https://pan.baidu.com/s/1c2fX3EC ,这本书是iOS开发者必读的书之一,写得很不错,欢迎大家下载阅读.书的封面如下,故也称狮子书: . (1)多线程会遇到的问题 . 多线程会出现什么问题呢?当多个线程对同一

iOS多线程开发小demo

首先演示一下主线程的阻塞 // DYFViewController.m // 623-01-阻塞多线程 // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @end @implementation DYFViewCon

iOS多线程开发小demo5 线程间的通信

// DYFViewController.m // 623-06-线程间的通信 // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @property (weak, nonatomic) IBOutlet UIImag

iOS多线程开发小demo7 GCD队列组

// DYFViewController.m // 623-08-队列组 // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @property (weak, nonatomic) IBOutlet UIImageVi

iOS多线程开发小demo4,线程的同步问题

// DYFViewController.m // 623-05-线程同步问题 // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @property (nonatomic, assign) int leftCount

iOS多线程开发小demo2,NSThread篇

用NSThread创建子线程的3种方法 // DYFViewController.m // 623-02-pthread // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" #import <pthread.h> @interface DYFViewController