betway必威手机版 > betway必威手机版官网 > 细说GCD(Grand Central Dispatch)如何用

原标题:细说GCD(Grand Central Dispatch)如何用

浏览次数:100 时间:2020-03-18

文中较详细介绍GCD队列,各个GCD使用方法,实举例何运用Dispatch Source监听系统底层对象,解析不一致锁的属性比较,实例GCD死锁情状。文中的Demo在此 对着随笔试着来调demo体会更加深哦,细细嚼消化吸收好:卡塔尔

GCD是归属系统级其他线程管理,在Dispatch queue中实行要求进行的天职,品质相当高
·基于队列的产出编制程序API,聚集管理大家一道使用的线程池
·公开的5个不等队列:运转在主线程的main queue,3个分裂优先级的后台队列(High Priority Queue,Default Priority Queue,Low Priority Queue卡塔尔国,以至一个优先级更低的后台队列Background Priority Queue (用于I/O)
·可创制自定义队列:串行或并行队列。自定义平常坐落于Default Priority Queue和Main Queue里。
·操作是在二十四线程上依旧看队列的项目和奉行格局,并行队列异步实践技艺在八线程,并列队列同步奉行就只会在这里个相互作用队列在队列中被分配的非常线程实践。

GCD是苹果为开辟者提供的体系等级的线程管理api,开荒进程中特别对多为重质量做了优化,所以在dispatch queue中进行任务品质相当高。

GCD归属系统级的线程管理,在Dispatch queue中推行供给实行的职务质量特其余高。GCD这块已经开源,地址 queue,用来保管先进来的天职先获得实行。

系统的三个连串

//全局队列,一个并行的队列
dispatch_get_global_queue
//主队列,主线程中的唯一队列,一个串行队列
dispatch_get_main_queue

GCD概要

  • 和operation queue同样都以基于队列的面世编制程序API,底层使用的是线程池的技巧,聚集管理大家一同应用的线程池。
  • 系统提供多少个不等的大局队列
    • main queue 主线程队列,也是UI更新的线程
    • 四个不等优先级的队列(High Priority Queue,Default Priority Queue,Low Priority Queue),甚至一个前期级更低的后台队列Background Priority Queue
    • 可创建自定义队列:串行或并列队列。自定义队列平时坐落于Default Priority Queue和Main Queue里。
    • 操作是在二十四线程上也许单线程首假设看队列的门类和实践情势,并行队列异步执行技巧在十二线程,并行队列同步实行就只会在主线程推行了
  • 和operation queue相近都以基于队列的面世编程API,他们通过聚集管理大家齐声应用的线程池。
  • 理解的5个例外队列:运维在主线程中的main queue,3个不等优先级的后台队列(High Priority Queue,Default Priority Queue,Low Priority Queue),以致二个事前级更低的后台队列Background Priority Queue
  • 可创建自定义队列:串行或并列队列。自定义平时坐落于Default Priority Queue和Main Queue里。
  • 操作是在七十四线程上照旧单线程首若是看队列的类别和实行情势,并行队列异步实践本领在多线程,并行队列同步试行就只会在主线程实践了

自定义队列

//串行队列
dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)
//并行队列
dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT)

基本概念

  • 系统提供的多个正规队列
//全局队列,是一个并行队列,可以设置不同的优先级dispatch_get_globle_queue//主队列,主线程中的唯一队列,是一个串行队列dispatch_get_main_queue
  • 自定义队列
//串行队列dispatch_queue_create("com.fineway.serialqueue",DISPATCH_QUEUE_SERIAL);//并行队列dispatch_queue_create("com.fineway.coucurrent",DISPATCH_QUEUE_CONCURRENT);
  • 一块异步线程的创办
//同步线程dispatch_sync(..., ^//异步线程dispatch_async(..., ^
  • Serial:又叫private dispatch queues,同不经常候只实行三个职务。Serial queue常用于同盟访谈特定的能源或数额。当您创建七个Serial queue时,即便个别是一块,但serial queue之间是出新实施。
  • Main dispatch queue:全局可用的serial queue,在应用程序主线程上施行职分。
  • Concurrent:又叫global dispatch queue,能够现身的试行三个职责,但执行到位顺序是轻巧的。系统提供七个全局并发队列,那五个类别有着相应的优先级,客户是不可见创建全局队列的,只好获得。
dispatch_queue_t queue;queue = dispatch_get_globle_queue( DISPATCH_QUEUE_PEIORITY_HIGH,0);
  • user create queue:创制自个儿定义的队列,能够用dispatch_queue_create函数,函数有八个参数,第四个自定义的队列名,第3个参数是队列类型,默认NULL或者DISPATCH_QUEUE_SE奔驰M级IAL的是串行,参数为DISPATCH_QUEUE_CONCUWranglerRENT为并行队列。
dispatch_queue_t queue ;queue = dispatch_queue_create("com.fineway.concurrent",DISPATCH_QUEUEU_CONCURRENT);
  • 自定义队列的开始时期级:能够经过dipatch_queue_attr_make_with_qos_class或dispatch_set_target_queue方法设置队列的刚开始阶段级
//dipatch_queue_attr_make_with_qos_classdispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, -1);dispatch_queue_t queue = dispatch_queue_create("com.fineway.serialqueue", attr);//dispatch_set_target_queuedispatch_queue_t queue = dispatch_queue_create("com.fineway.serialqueue",NULL); //需要设置优先级的queuedispatch_queue_t referQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //参考优先级dispatch_set_target_queue(queue, referQueue); //设置queue和referQueue的优先级一样
  • dispatch_set_target_queue:可以安装优先级,也得以设置队列层级体系,举例让四个串行和互相队列在统一七个串行队列里串行推行,如下
dispatch_queue_t serialQueue = dispatch_queue_create("com.fineway.serialqueue", DISPATCH_QUEUE_SERIAL);dispatch_queue_t firstQueue = dispatch_queue_create("com.fineway.serialqueue", DISPATCH_QUEUE_SERIAL);dispatch_queue_t secondQueue = dispatch_queue_create("com.fineway.serialqueue", DISPATCH_QUEUE_CONCURRENT);dispatch_set_target_queue(firstQueue, serialQueue);dispatch_set_target_queue(secondQueue, serialQueue); dispatch_async(firstQueue, ^{ NSLog; [NSThread sleepForTimeInterval:3.f];});dispatch_async(secondQueue, ^{ NSLog; [NSThread sleepForTimeInterval:2.f];});dispatch_async(secondQueue, ^{ NSLog; [NSThread sleepForTimeInterval:1.f];});

协助实行异步线程创制

//同步线程
dispatch_sync(..., ^(block))
//异步线程
dispatch_async(..., ^(block))

队列类型

队列类型暗中认可是串行的,假使创设队列的时候参数是NULL,队列是串行的,队列参数是DISPATCH_QUEUE_CONCU纳瓦拉RENT时,队列是并行的,能够并且进行多少个block。

  • 曾几何时使用何种队列类型
    • 主队列:队列中有任务达成要求更新UI时,dispatch_after在这里类别型中运用。
    • 并发队列:用来试行与UI非亲非故的后台义务,dispatch_sync放在那,方便等待职责令功进展继续管理或和dispatch barrier同步。dispatch groups放在这里处也不易。
    • 自定义顺序队列:顺序实践后台职责并追踪它时。那样做何况唯有三个职分在执行可以堤防能源角逐。dipatch barriers解决读写锁难点的放在那各处理。dispatch groups也是放在那。
  • 系统职业多少个连串

队列

·串行队列,相同的时间只实行多个任务
·主队列,全局可用的串行队列,在主线程上实践职分
·并行队列,能够并发实施多个职责,然则各类是大肆的,系统提供八个全局并发队列,那多少个系列有对应的刚开始阶段级

dipatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);

·自定义队列能够行使dispatch_queue_create函数,函数有四个参数,第一个是自定义的系列名,第一个是队列类型,暗许NULL。

dispatch_queue_t queue
queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

·自定义队列的优先级,能够经过dispatch_queue_attr_make_with_qos_class或dispatch_set_target_queue方法设置队列的先行级

//dipatch_queue_attr_make_with_qos_class
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, -1);
dispatch_queue_t queue = dispatch_queue_create("serialQueue", attr);

//dispatch_set_target_queue
dispatch_queue_t queue = dispatch_queue_create("concurrentQueue",NULL); //需要设置优先级的queue
dispatch_queue_t referQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //参考优先级
dispatch_set_target_queue(queue, referQueue); //设置queue和referQueue的优先级一样

dispatch_set_target_queue: 能够安装优先级,也能够设置队列层级类别,比方让多个串行和相互作用队列在联合叁个串行队列里串行推行,如下

dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t firstQueue = dispatch_queue_create("com.starming.gcddemo.firstqueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t secondQueue = dispatch_queue_create("com.starming.gcddemo.secondqueue", DISPATCH_QUEUE_CONCURRENT);

dispatch_set_target_queue(firstQueue, serialQueue);
dispatch_set_target_queue(secondQueue, serialQueue);

dispatch_async(firstQueue, ^{
    NSLog(@"1");
    [NSThread sleepForTimeInterval:3.f];
});
dispatch_async(secondQueue, ^{
    NSLog(@"2");
    [NSThread sleepForTimeInterval:2.f];
});
dispatch_async(secondQueue, ^{
    NSLog(@"3");
    [NSThread sleepForTimeInterval:1.f];
});

5种队列,主队列(main queue),二种通用调治队列,自个儿定制的种类。分别是
QOS_CLASS_USER_INTERACTIVE:user interactive等级表示职责需求被当即实施提供好的体验,用来更新UI,响应事件等。这一个阶段最棒保障小圈圈。
QOS_CLASS_USER_INITIATED:user initiated等级表示任务由UI发起异步推行。适用途景是索要立时结果同临时间又有什么不可一连互相的时候。
QOS_CLASS_UTILITY:utility等第表示需求长日子运作的职务,伴有客商可知进程提示器。平日会用来做总结,I/O,互联网,持续的数据填充等职务。这几个职务节约财富。
QOS_CLASS_BACKGROUND:background等第表示客商不会开采的职分,使用它来管理预加载,恐怕无需客商交互作用和对时间不灵动的职分。

曾几何时使用何种队列类型
dispatch_once 平时拿来成立单例
dispatch_async 叁个异步API

//代码框架
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     // 耗时的操作
     dispatch_async(dispatch_get_main_queue(), ^{
          // 更新界面
     });
});

//下载图片的示例
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
     NSData * data = [[NSData alloc]initWithContentsOfURL:url];
     UIImage *image = [[UIImage alloc]initWithData:data];
     if (data != nil) {
          dispatch_async(dispatch_get_main_queue(), ^{
               self.imageView.image = image;
          });
     }
});

dispatch_after延后试行

- (void)foo
{
     double delayInSeconds = 2.0;
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delayInSeconds * NSEC_PER_SEC));
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
          [self bar];
     });
}

个中用的宏有各样

 #define NSEC_PER_SEC 1000000000ull //每秒有多少纳秒
 #define USEC_PER_SEC 1000000ull    //每秒有多少毫秒
 #define NSEC_PER_USEC 1000ull      //每毫秒有多少纳秒

假使要代表一秒能够那样写

dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
dispatch_time(DISPATCH_TIME_NOW, 1000 * USEC_PER_SEC);
dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC * NSEC_PER_USEC);

关于dispatch_once

使用dispatch_once创造单例时,要确定保证dispatch_once_t是全局或然static变量,保障只是创制二次。

  (AppDataSource *)shareAppDataSource{ static AppDataSource *shareAppDataSource = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ shareAppDataSource = [[self alloc] init]; }); return shareAppDataSource;}

dispatch_barrier_async

选择Barrier Task方法Dispatch Barrier消除三十二线程并发读写同一个能源爆发死锁
Dispatch Barrier确定保障提交的闭包是钦赐队列中在特准时刻独一在施行的三个。在全部先于Dispatch Barrier的职务都达成的动静下那一个闭包才起来进行。轮到那么些闭包时barrier会实行那一个闭包并且保障队列在那进度不会进行其余职务。闭包落成后队列恢复生机。需求在意dispatch_barrier_async只在温馨创办的连串上有这种效应,在大局并发队列和串行队列上,效果和dispatch_sync一样

//创建队列
self.isolationQueue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_CONCURRENT);
//改变setter
- (void)setCount:(NSUInteger)count forKey:(NSString *)key
{
     key = [key copy];
     //确保所有barrier都是async异步的
     dispatch_barrier_async(self.isolationQueue, ^(){
          if (count == 0) {
               [self.counts removeObjectForKey:key];
          } else {
               self.counts[key] = @(count);
          }
     });
}
- (void)dispatchBarrierAsyncDemo {
    //防止文件读写冲突,可以创建一个串行队列,操作都在这个队列中进行,没有更新数据读用并行,写用串行。
    dispatch_queue_t dataQueue = dispatch_queue_create("com.starming.gcddemo.dataqueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(dataQueue, ^{
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"read data 1");
    });
    dispatch_async(dataQueue, ^{
        NSLog(@"read data 2");
    });
    //等待前面的都完成,在执行barrier后面的
    dispatch_barrier_async(dataQueue, ^{
        NSLog(@"write data 1");
        [NSThread sleepForTimeInterval:1];
    });
    dispatch_async(dataQueue, ^{
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"read data 3");
    });
    dispatch_async(dataQueue, ^{
        NSLog(@"read data 4");
    });
}

关于dispatch_async

异步试行api,将任务切换成专门的学业线程中实施,防止拥塞主线程。譬如读取网络数据,大数量IO,还应该有大批量数目标数据库读写,当时急需在另多个线程中拍卖,然后布告主线程更新分界面,GCD使用起来比NSThread和NSOperation方法要简明方便。

//代码框架,异步执行,完成后主线程更新UIdispatch_async(dispatch_get_globle_queue(), ^{ // do actual processing here dispatch_async(dispatch_get_main_queue(), ^{ handler; });

下载图片示例

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"]; NSData * data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if (data != nil) { dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; }); }});
//全局队列,一个并行的队列dispatch_get_global_queue//主队列,主线程中的唯一队列,一个串行队列dispatch_get_main_queue

dispatch_apply进行急速迭代

左近for循环,不过在并发队列的情况下dispatch_apply会并发推行block职责

for (size_t y = 0; y < height;   y) {
     for (size_t x = 0; x < width;   x) {
          // Do something with x and y here
     }
}
//因为可以并行执行,所以使用dispatch_apply可以运行的更快
- (void)dispatchApplyDemo {
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_apply(10, concurrentQueue, ^(size_t i) {
        NSLog(@"%zu",i);
    });
    NSLog(@"The end"); //这里有个需要注意的是,dispatch_apply这个是会阻塞主线程的。这个log打印会在dispatch_apply都结束后才开始执行
}

dispatch_apply能防止线程爆炸,因为GCD会管理现身

- (void)dealWiththreadWithMaybeExplode:(BOOL)explode {
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    if (explode) {
        //有问题的情况,可能会死锁
        for (int i = 0; i < 999 ; i  ) {
            dispatch_async(concurrentQueue, ^{
                NSLog(@"wrong %d",i);
                //do something hard
            });
        }
    } else {
        //会优化很多,能够利用GCD管理
        dispatch_apply(999, concurrentQueue, ^(size_t i){
            NSLog(@"correct %zu",i);
            //do something hard
        });
    }
}

关于dispatch_after延后试行

延时提交block,不均等与延时随时实行。介绍dispatch_after在此以前先掌握一下dispatch time.

dispatch_time_t dispatch_time ( dispatch_time_t when, int64_t delta );
  • 首先个参数表示从什么日子开始,DISPATCH_TIME_NOW代表从前段时间初阶
  • 其次个参数表示延时的时间,单文是纳秒,一分钟等于1000000000微秒,系统提供部分宏定义来简化总计
#define NSEC_PER_SEC 1000000000ull //每秒有多少纳秒 #define USEC_PER_SEC 1000000ull //每秒有多少毫秒 #define NSEC_PER_USEC 1000ull //每毫秒有多少纳秒

一旦想要延时一秒,能够这么写

dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);dispatch_time(DISPATCH_TIME_NOW, 1000 * USEC_PER_SEC);dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC * NSEC_PER_USEC);

延时示范落成

double delayInSeconds = 2.0; //延时时间dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,  (delayInSeconds * NSEC_PER_SEC)); //从现在起延时delayInSeconds执行dispatch_after(popTime, dispatch_get_main_queue(), ^{ [self bar]; });//主线程延迟2s后执行bar方法。
  • 自定义队列

Block组合Dispatch_groups

dispatch groups是挑升用来监视三个异步任务。dispatch_group_t实例用来追踪分裂队列中的分化职分。

当group里有着事件都产生GCD API有二种情势发送公告,第一种是dispatch_group_wait,会卡住当前进程,等富有职责都产生或等候超时。第三种方式是运用dispatch_group_notify,异步施行闭包,不会窒碍。

- (void)dispatchGroupWaitDemo {
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    //在group中添加队列的block
    dispatch_group_async(group, concurrentQueue, ^{
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"1");
    });
    dispatch_group_async(group, concurrentQueue, ^{
        NSLog(@"2");
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"go on");
}

使用dispatch_group_notify的例子

//dispatch_group_notify
- (void)dispatchGroupNotifyDemo {
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, concurrentQueue, ^{
        NSLog(@"1");
    });
    dispatch_group_async(group, concurrentQueue, ^{
        NSLog(@"2");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
    NSLog(@"can continue");

}

//dispatch_group_wait
- (void)dispatchGroupWaitDemo {
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    //在group中添加队列的block
    dispatch_group_async(group, concurrentQueue, ^{
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"1");
    });
    dispatch_group_async(group, concurrentQueue, ^{
        NSLog(@"2");
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"can continue");
}

怎么着对现存API使用dispatch_group_t

//NSURLConnection也可以这样做
  (void)withGroup:(dispatch_group_t)group
     sendAsynchronousRequest:(NSURLRequest *)request
     queue:(NSOperationQueue *)queue
     completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
{
     if (group == NULL) {
          [self sendAsynchronousRequest:request
               queue:queue
               completionHandler:handler];
     } else {
          dispatch_group_enter(group);
          [self sendAsynchronousRequest:request
                    queue:queue
                    completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
               handler(response, data, error);
               dispatch_group_leave(group);
          }];
     }
}

·dispatch_group_async等价于dispatch_group_enter() 和 dispatch_group_leave()的组合。
·dispatch_group_enter(卡塔尔 必得运营在 dispatch_group_leave() 之前。
·dispatch_group_enter() 和 dispatch_group_leave(卡塔尔国 要求成对出现的

关于dispatch_barrier_async

Dispatch Barrier确定保证提交的闭包是钦赐队列中在一准期刻独一在进行的一个。在全部先于Dispatch Barrier的天职都成功的状态下那一个闭包才起来举行。轮到那几个闭包时barrier会施行这些闭包何况有限帮助队列在这里进度不会试行其余任务。闭包达成后队列恢复生机。供给注意dispatch_barrier_async只在自个儿成立的队列上有这种效果,在全局并发队列和串行队列上,效果和dispatch_sync一样。

赋值示例

self.isolationQueue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_CONCURRENT);- setCount:(NSUInteger)count forKey:(NSString *)key{ key = [key copy]; //确保所有barrier都是async异步的 dispatch_barrier_async(self.isolationQueue, ^(){ if (count == 0) { [self.counts removeObjectForKey:key]; } else { self.counts[key] = @; } });}

//防止文件读写冲突,可以创建一个串行队列,操作都在这个队列中进行,没有更新数据读用并行,写用串行。 dispatch_queue_t dataQueue = dispatch_queue_create("com.fineway.dataqueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(dataQueue, ^{ [NSThread sleepForTimeInterval:2.f]; NSLog(@"read data 1"); }); dispatch_async(dataQueue, ^{ NSLog(@"read data 2"); }); //等待前面的都完成,在执行barrier后面的 dispatch_barrier_async(dataQueue, ^{ NSLog(@"write data 1"); [NSThread sleepForTimeInterval:1]; }); dispatch_async(dataQueue, ^{ [NSThread sleepForTimeInterval:1.f]; NSLog(@"read data 3"); }); dispatch_async(dataQueue, ^{ NSLog(@"read data 4"); });

Dispatch Block

关于dispatch_apply

功用:把一项职分交给到行列中反复实施,具体是并行推行依旧串行实行由队列本身决定.注意,dispatch_apply不会立即回到,在实践实现后才会回来,是三只的调用。

for (size_t y = 0; y < height;   y) { for (size_t x = 0; x < width;   x) { // Do something with x and y here }}//因为可以并行执行,所以使用dispatch_apply可以运行的更快- dispatchApplyDemo { dispatch_queue_t concurrentQueue = dispatch_queue_create("com.fineway.concurrentqueue", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(10, concurrentQueue, ^ { NSLog; }); NSLog(@"The end"); //这里有个需要注意的是,dispatch_apply这个是会阻塞当前线程的。这个log打印会在dispatch_apply都结束后才开始执行}

dispatch_apply能够免止线程爆炸,因为GCD可以实行线程优化

- dealWiththreadWithMaybeExplode:explode { dispatch_queue_t concurrentQueue = dispatch_queue_create("com.fineway.concurrentqueue",DISPATCH_QUEUE_CONCURRENT); if  { //有问题的情况,可能会死锁 for (int i = 0; i < 999 ; i  ) { dispatch_async(concurrentQueue, ^{ NSLog(@"wrong %d",i); //do something hard }); } } else { //会优化很多,能够利用GCD管理 dispatch_apply(999, concurrentQueue, ^{ NSLog(@"correct %zu",i); //do something hard }); }}
//串行队列dispatch_queue_create("com.starming.serialqueue", DISPATCH_QUEUE_SERIAL)//并行队列dispatch_queue_create("com.starming.concurrentqueue", DISPATCH_QUEUE_CONCURRENT)

·创建block

- (void)createDispatchBlock {
    //normal way
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_block_t block = dispatch_block_create(0, ^{
        NSLog(@"run block");
    });
    dispatch_async(concurrentQueue, block);

    //QOS way
    dispatch_block_t qosBlock = dispatch_block_create_with_qos_class(0, QOS_CLASS_USER_INITIATED, -1, ^{
        NSLog(@"run qos block");
    });
    dispatch_async(concurrentQueue, qosBlock);
}

·dispatch_block_wait:可以依照dispatch block 来安装等待时间,参数DISPATCH_TIME_FOREVE逍客会平素等候block甘休

- (void)dispatchBlockWaitDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t block = dispatch_block_create(0, ^{
        NSLog(@"star");
        [NSThread sleepForTimeInterval:5.f];
        NSLog(@"end");
    });
    dispatch_async(serialQueue, block);
    //设置DISPATCH_TIME_FOREVER会一直等到前面任务都完成
    dispatch_block_wait(block, DISPATCH_TIME_FOREVER);
    NSLog(@"ok, now can go on");
}

·dispatch_block_notify:能够监视内定dispatch block甘休,然后再出席叁个block到行列中。三个参数分别为,第4个是内需监视的block,第二个参数是要求付出实践的行列,第多个是待加入到行列中的block

- (void)dispatchBlockNotifyDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t firstBlock = dispatch_block_create(0, ^{
        NSLog(@"first block start");
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"first block end");
    });
    dispatch_async(serialQueue, firstBlock);
    dispatch_block_t secondBlock = dispatch_block_create(0, ^{
        NSLog(@"second block run");
    });
    //first block执行完才在serial queue中执行second block
    dispatch_block_notify(firstBlock, serialQueue, secondBlock);
}

·dispatch_block_cancel:iOS8后GCD支持对dispatch block的取消

- (void)dispatchBlockCancelDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t firstBlock = dispatch_block_create(0, ^{
        NSLog(@"first block start");
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"first block end");
    });
    dispatch_block_t secondBlock = dispatch_block_create(0, ^{
        NSLog(@"second block run");
    });
    dispatch_async(serialQueue, firstBlock);
    dispatch_async(serialQueue, secondBlock);
    //取消secondBlock
    dispatch_block_cancel(secondBlock);
}

关于dispatch_group

dispatch groups是特别用来监视七个异步任务。dispatch_group_t实例用来追踪分裂队列中的不一致职分。

当group里具有事件都产生GCD API有二种方式发送文告,第一种是dispatch_group_wait,会拥塞当前经过,等具备职务都做到或等待超时。第三种方法是利用dispatch_group_notify,异步实施闭包,不会卡住。

//dispatch_group_notify- dispatchGroupNotifyDemo { dispatch_queue_t concurrentQueue = dispatch_queue_create("com.fineway.concurrentqueue",DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, concurrentQueue, ^{ NSLog; dispatch_group_async(group, concurrentQueue, ^{ NSLog; dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog; }); NSLog(@"can continue"); }//dispatch_group_wait- dispatchGroupWaitDemo { dispatch_queue_t concurrentQueue = dispatch_queue_create("com.fineway.concurrentqueue",DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create();//在group中添加队列的block dispatch_group_async(group, concurrentQueue, ^{ [NSThread sleepForTimeInterval:2.f]; NSLog; dispatch_group_async(group, concurrentQueue, ^{ NSLog; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); NSLog(@"can continue");}

dispatch io读取文件的艺术接近于上面包车型地铁不二秘技,多少个线程去读取文件的切条数据,对于大的数据文件这样会比单线程要快超多。

dispatch_async(queue,^{/*read 0-99 bytes*/});dispatch_async(queue,^{/*read 100-199 bytes*/});dispatch_async(queue,^{/*read 200-299 bytes*/});
  • dispatch_io_create:创建dispatch io
  • dispatch_io_set_low_water:钦点切割文件大小
  • dispatch_io_read:读取切割的文书然后归拢。苹果系统日志API里用到了这么些技巧,能够在那查看:相关资料
pipe_q = dispatch_queue_create("PipeQ", NULL);//创建pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^{ close;*out_fd = fdpair[1];//设置切割大小dispatch_io_set_low_water(pipe_channel, SIZE_MAX);dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){ if  { size_t len = dispatch_data_get_size; if (len > 0) { //对每次切块数据的处理 const char *bytes = NULL; char *encoded; uint32_t eval; dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len); encoded = asl_core_encode_buffer(bytes, len); asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded); free; eval = _asl_evaluate_send(NULL, aux, -1); _asl_send_message(NULL, eval, aux, NULL); asl_msg_release; dispatch_release; } } if  { //semaphore  1使得不需要再等待继续执行下去。 dispatch_semaphore_signal; dispatch_release(pipe_channel); dispatch_release; }});

Dispatch Source用于监听系统的最底层对象,比方文件描述符,Mach端口,连续信号量等。首要管理的事件如下表方法 表明DISPATCH_SOURCE_TYPE_DATA_ADD 数据增添DISPATCH_SOURCE_TYPE_DATA_OR 数据ORDISPATCH_SOURCE_TYPE_MACH_SEND Mach端口发送DISPATCH_SOURCE_TYPE_MACH_RECV Mach端口选用DISPATCH_SOURCE_TYPE_MEMO普拉多YPRESSURE 内部存款和储蓄器意况DISPATCH_SOURCE_TYPE_PROC 进度事件DISPATCH_SOURCE_TYPE_READ 读数据DISPATCH_SOURCE_TYPE_SIGNAL 信号DISPATCH_SOURCE_TYPE_TIMER 定时器DISPATCH_SOURCE_TYPE_VNODE 文件系统变化DISPATCH_SOURCE_TYPE_W库罗德ITE 文件写入

方法

  • dispatch_source_create:创设dispatch source,创设后会处于挂起状态实行事件接收,须求安装事件管理handler举行事件管理。
  • dispatch_source_set_event_handler:设置事件管理handler
  • dispatch_source_set_cancel_handler:事件撤废handler,就是在dispatch source释放前做些清理的事。
  • dispatch_source_cancel:关闭dispatch source,设置的事件管理handler不会被推行,已经推行的风浪handler不会吊销。

其他一种保证同步的艺术。使用dispatch_semaphore_signal加1dispatch_semaphore_wait减1,为0时守候的装置方法来达到线程同步的指标和一同锁肖似能够消除财富抢占的标题。

 //创建semaphore dispatch_semaphore_t semaphore = dispatch_semaphore_create; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog; [NSThread sleepForTimeInterval:1.f]; NSLog(@"semaphore  1"); dispatch_semaphore_signal(semaphore); // 1 semaphore }); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//知道signal发出后才执行 NSLog(@"continue");

只好挂起未进行的block,不能够挂起已经奉行只怕正在奉行的block

当串行队列之中同步执行该串行队列的时候,就能发生死锁,化解的方法正是将联手的串行队列放到其余一个线程就能够消除。

//示例1 NSLog; dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSLog; NSLog;//只打印1,2和3相互等待,不会打印,形成死锁//示例2 dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL); NSLog; dispatch_async(serialQueue, ^{ NSLog; //串行队列里面同步一个串行队列就会死锁 dispatch_sync(serialQueue, ^{ NSLog; NSLog; NSLog;//只打印1 5 2,3与4不会打印//示例3 NSLog; dispatch_async(dispatch_get_global_queue, ^{ NSLog; //将同步的串行队列放到另外一个线程就能够解决 dispatch_sync(dispatch_get_main_queue(), ^{ NSLog; NSLog; NSLog;//示例4 dispatch_async(dispatch_get_global_queue, ^{ NSLog; //回到主线程发现死循环后面就没法执行了 dispatch_sync(dispatch_get_main_queue(), ^{ NSLog; NSLog; NSLog; //死循环 while  { // }
  • 一道异步线程成立

选拔dispatch block object(调节块)在任务实施前开展撤销

·dispatch block object可认为队列中的对象设置

Dispatch IO文件操作

dispatch io读取文件的点子临近于上边包车型地铁主意,多个线程去读取文件的切块数据,对于大的数据文件这样会比单线程要快相当多。
·dispatch_io_create:创建dispatch io
·dispatch_io_set_low_water:钦点切割文件大小
·dispatch_io_read:读取切割的文本然后合并。

//同步线程dispatch_sync(..., ^//异步线程dispatch_async(..., ^

Dispatch Semaphore的介绍

此外一种保障同步的不二等秘书技。使用dispatch_semaphore_signal加1dispatch_semaphore_wait减1,为0时守候的安装方法来实现线程同步的指标和协助举行锁同样能够缓和能源抢占的主题素材。

//dispatch semaphore
- (void)dispatchSemaphoreDemo {
    //创建semaphore
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"semaphore  1");
        dispatch_semaphore_signal(semaphore); // 1 semaphore
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"continue");
}
  • 塞里al:又叫private dispatch queues,同一时间只进行一个职责。Serial queue常用于同盟访谈特定的能源或数量。当您创建多少个Serial queue时,固然个别是一块,但serial queue之间是出新试行。
  • Main dispatch queue:全局可用的serial queue,在应用程序主线程上举行职务。
  • Concurrent:又叫global dispatch queue,能够现身的推行多少个职务,但奉行到位顺序是自由的。系统提供四个全局并发队列,那多少个连串有那对应的优先级,顾客是不可以看见成立全局队列的,只可以取得。

·NSRecursiveLock:递归锁,能够在三个线程中频频获取锁不会变成死锁,那些进度会记录获取锁和释放锁的次数来完毕何时释放的法力。
·NSDistributedLock:布满锁,基于文件措施的锁机制,可以跨进度访谈。
·NSConditionLock:条件锁,客商定义法则,确认保证二个线程能够获取知足一定条件的锁。因为线程间竞争会提到到条件锁检查测试,系统调用上下切换频仍招致耗费时间是多少个锁里最长的。
·OSSpinLock:自旋锁,不进去底子,裁减上下文切换,品质最高,但抢占多时会占用超多cpu,这时候使用pthread_mutex较好。
·pthread_mutex_t:同步锁基于C语言,底层api品质高,使用方法和任何的好像。
@synchronized:特别简明。

dispatch_suspend和dispatch_resume挂起和回复队列

dispatch_suspend这里挂起不会停顿正在实行的block,只是能够暂停还未有实施的block。

dipatch_queue_t queue;queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
  • user create queue:成立本人定义的队列,可以用dispatch_queue_create函数,函数有五个参数,第一个自定义的体系名,第三个参数是队列类型,暗许NULL可能DISPATCH_QUEUE_SE酷威IAL的是串行,参数为DISPATCH_QUEUE_CONCUTucsonRENT为并行队列。
dispatch_queue_t queuequeue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
  • 自定义队列的事情发生前级:可以透过dipatch_queue_attr_make_with_qos_class或dispatch_set_target_queue方法设置队列的事前级
//dipatch_queue_attr_make_with_qos_classdispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, -1);dispatch_queue_t queue = dispatch_queue_create("com.starming.gcddemo.qosqueue", attr);//dispatch_set_target_queuedispatch_queue_t queue = dispatch_queue_create("com.starming.gcddemo.settargetqueue",NULL); //需要设置优先级的queuedispatch_queue_t referQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //参考优先级dispatch_set_target_queue(queue, referQueue); //设置queue和referQueue的优先级一样
  • dispatch_set_target_queue:能够设置优先级,也得以安装队列层级体系,比方让八个串行和相互队列在群集三个串行队列里串行试行,如下
dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);dispatch_queue_t firstQueue = dispatch_queue_create("com.starming.gcddemo.firstqueue", DISPATCH_QUEUE_SERIAL);dispatch_queue_t secondQueue = dispatch_queue_create("com.starming.gcddemo.secondqueue", DISPATCH_QUEUE_CONCURRENT);dispatch_set_target_queue(firstQueue, serialQueue);dispatch_set_target_queue(secondQueue, serialQueue);dispatch_async(firstQueue, ^{ NSLog; [NSThread sleepForTimeInterval:3.f];});dispatch_async(secondQueue, ^{ NSLog; [NSThread sleepForTimeInterval:2.f];});dispatch_async(secondQueue, ^{ NSLog; [NSThread sleepForTimeInterval:1.f];});

队列私下认可是串行的,假若设置改参数为NULL会按串行管理,只可以进行多少个独立的block,队列也得以是互为的,同不经常常候实行几个block

- init;{ self = [super init]; if (self != nil) { NSString *label = [NSString stringWithFormat:@"%@.isolation.%p", [self class], self]; self.isolationQueue = dispatch_queue_create([label UTF8String], 0); label = [NSString stringWithFormat:@"%@.work.%p", [self class], self]; self.workQueue = dispatch_queue_create([label UTF8String], 0); } return self;}

5种队列,主队列(main queue),种种通用调整队列,自个儿定制的队列。多种通用调整队列为

  • QOS_CLASS_USER_INTERACTIVE:user interactive品级表示职务供给被及时实践提供好的心得,用来更新UI,响应事件等。这几个品级最棒涵养小框框。
  • QOS_CLASS_USER_INITIATED:user initiated品级表示职责由UI发起异步执行。适用途景是内需登时结果还要又足以继续相互的时候。
  • QOS_CLASS_UTILITY:utility品级表示需求长日子运作的职分,伴有客户可以预知进程提醒器。日常会用来做总结,I/O,互联网,持续的数码填充等任务。这些职分节约财富。
  • QOS_CLASS_BACKGROUND:background等第表示客户不会开采的天职,使用它来管理预加载,也许没有必要客户人机联作和对时间不灵敏的任务。

示范:后台加载突显图片

override func viewDidLoad() { super.viewDidLoad() dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) { // 将工作从主线程转移到全局队列中,这是dispatch_async调用,异步提交保证调用线程会继续执行下去,这样viewDidLoad在主线程上能够更早完成, let overlayImage = self.faceOverlayImageFromImage(self.image) dispatch_async(dispatch_get_main_queue { // 新图完成,把一个闭包加入主线程用来更新UIImageView,只有在主线程能操作UIKit。 self.fadeInNewImage(overlayImage) // 更新UI } }}

何时使用何种队列类型

  • 主队列:队列中有任务到位供给更新UI时,dispatch_after在此连串型中采用。
  • 并发队列:用来实施与UI非亲非故的后台任务,dispatch_sync放在这里处,方便等待职责到位进展三番若干次管理或和dispatch barrier同步。dispatch groups放在那处也未可厚非。
  • 自定义顺序队列:顺序推行后台职务并追踪它时。那样做并且独有一个任务在实施能够卫戍财富角逐。dipatch barriers解决读写锁难题的坐落于这里管理。dispatch groups也是放在这里边。

能够利用下面包车型大巴方法简化QoS等第参数的写法

var GlobalMainQueue: dispatch_queue_t { return dispatch_get_main_queue()}var GlobalUserInteractiveQueue: dispatch_queue_t { return dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.value), 0)}var GlobalUserInitiatedQueue: dispatch_queue_t { return dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)}var GlobalUtilityQueue: dispatch_queue_t { return dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)}var GlobalBackgroundQueue: dispatch_queue_t { return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)}//使用起来就是这样,易读而且容易看出在使用哪个队列dispatch_async(GlobalUserInitiatedQueue) { let overlayImage = self.faceOverlayImageFromImage(self.image) dispatch_async(GlobalMainQueue) { self.fadeInNewImage(overlayImage) }}

dispatch_once_t要是大局或static变量,保险dispatch_once_t只有一份实例

  (UIColor *)boringColor;{ static UIColor *color; //只运行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ color = [UIColor colorWithRed:0.380f green:0.376f blue:0.376f alpha:1.000f]; }); return color;}

规划二个异步的API调用dispatch_async(卡塔尔,那个调用放在API的方法或函数中做。让API的使用者设置叁个回调解和管理理队列

- processImage:(UIImage *)image completionHandler:(BOOL success))handler;{ dispatch_async(self.isolationQueue, ^{ // do actual processing here dispatch_async(self.resultQueue, ^{ handler; });}

能够免止分界面会被一些耗费时间的操作卡死,举例读取互联网数据,大数量IO,还应该有大量数量的数据库读写,这个时候急需在另八个线程中管理,然后公告主线程更新分界面,GCD使用起来比NSThread和NSOperation方法要简明方便。

//代码框架dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗时的操作 dispatch_async(dispatch_get_main_queue(), ^{ // 更新界面 });});//下载图片的示例dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"]; NSData * data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if (data != nil) { dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; }); }});

本文由betway必威手机版发布于betway必威手机版官网,转载请注明出处:细说GCD(Grand Central Dispatch)如何用

关键词: 日记本 如何用 Grand GCD

上一篇:刺激战场网络异常登录失败,lol无法登陆问题汇

下一篇:没有了