GCD是iOS多线程中最经常使用的一种。须要明确的几点: 数据库
任务:block 多线程
队列:把任务放到队列里,队列先进先出的原则。 并发
串行队列:顺序,一个一个执行。 异步
并发队列:同时,同时执行不少个任务。 async
GCD中有俩个用来执行任务的函数。GCD里面的函数都是以dispatch开头的 函数
用同步的方式执行任务: dispatch_sync(对列, block);不会开启新线程,在当前线程执行 spa
用异步的方式执行任务:dispatch_async(对列, block);确定会开新线程,在新线程中执行。 线程
队列与同步异步的的组合方式共四类:分别看一下: code
若是是串行队列,sync同步方法的话,通常只要使用“同步”执行,串行队列添加的同步任务,会立马执行,与不用GCD的顺序是同样的。 对象
若是是串行队列,async异步执行的话,只会开一个新线程,并且全部任务都在这个新的线程里面一个一个顺序执行。
若是是并发队列,sync同步执行的话,不开新线程,顺序执行。与不用线程同样。
若是是并发队列,async异步执行的话,会开不少个线程,并发(不必定是一个一个的)执行。
总之若是是在同步的状况下,那么是不会开线程的,就是说同步的状况下多线程就失去了意义,只有异步的状况下才开线程。
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具有开启新线程的能力
异步:在新线程中执行任务,具有开启新线程的能力。
并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
总结;开不开线程,由执行的方法决定,同步不开,异步确定开,开多少线程,由队列决定,串行,最多开一个线程,并发,能够开多个,具体开多少个,由GCD底层决定,程序控制不了。
主队列;专门负责在主线程上调度任务,主队列:特色,不容许开新线程,异步执行:会开新线程,在新线程执行,若是在主线程异步方法的话,不开新线程,没有做用,至关于把任务放到主队列,但不须要立刻执行,等主队列空闲下来在执行。
若是在主队列同步方法的话,不开新线程,把任务放到主队列,但须要立刻执行,这会形成死锁现象。
一。实现,用法
1.create方法建立队列dispatch queue
1.1 建立一个串行队列:参数:队列标签,队列属性
//属性标签DISPATCH_QUEUE_SERIAL or NULL dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);
1.2建立一个并行队列:
dispatch_queue_t myConcurrrentDispatchQueue = dispatch_queue_create("com.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
1.3异步实现
dispatch_async(myConcurrrentDispatchQueue, ^{ NSLog(@"block on myConcurrentDispatchQueue"); });
2.get方法建立队列dispatch queue
2.1系统标准提供的dispatch_queue,主队列,全局队列的建立:
/* 系统标准提供的dispatch_queue,主队列,全局队列 */ dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue(); dispatch_queue_t globalDispatchQueueHign = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_queue_t globalDiaptchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
2.2调用
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* 可并行执行的处理 */ dispatch_async(dispatch_get_main_queue(), ^{ /* 在主线程中执行的处理 */ }); });
3
3.1 modify the priority of queue after which is created
dispatch_queue_t mySerialDispatchQueue1 = dispatch_queue_create("mySerialDispatchQueue1", NULL); dispatch_queue_t globalDispatchQueueBackgroud = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_set_target_queue(mySerialDispatchQueue1, globalDispatchQueueBackgroud); //dispatch_queue_create函数生成的队列无论是串行仍是并行的,队列,都是用与默认优先级Global Dispatch Queue相同执行优先级的线程。而改变已有queue(队列)的执行优先级要用dispatch_set_target_queue函数。第一个参数指数要变动的队列来,第二个参数取其优先级给第一个,函数执行完后第一个参数的队列的优先级和第二个参数的优先级相同,第二个参数不变。第一个参数若是制定系统提供的Main Dispatch Queue和Global Dispatch Queue则不知道会出现什么情况,所以这些均不可指定。
3.2 在指定时间后把block追加到队列中,而不是在指定时间后开始执行block,具体什么时候开始执行由CPU调度决定。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"waited at least three seconds"); });
3.3 Group(DISPATCH_QUEUE_CONCURRENT时,在追加到调度队列中的多个处理所有结束后想执行结束处理使用)
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue1, ^{ }); dispatch_group_async(group, queue1, ^{ }); dispatch_group_async(group, queue1, ^{ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ //上面的queue1中的block所有执行完毕,就会执行这个方法中的block }); // dispatch_group_wait(<#dispatch_group_t group#>, <#dispatch_time_t timeout#>)
3.4 dispatch_barrier_async 数据库访问和文件访问
dispatch_queue_t queue = dispatch_queue_create("xom.example.gcd.ForBarrier", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ }); dispatch_async(queue, ^{ }); // 上面的并行处理所有完成后才会执行下面的, dispatch_barrier_async(queue, ^{ }); // s上面的dispatch_barrier_async里的方法彻底执行完毕后才会执行下面的方法,下面的方法又开始并行执行。 dispatch_async(queue, ^{ }); dispatch_async(queue, ^{ });
3.5 dispatch_walltime函数用于计算绝对时间,使用struct timespec 类型的时间获得dispatch_time_t 类型的值。而struct timespec类型的时间能够很轻松的经过NSDate类对象生成
//下面函数可由NSDate类对象获取能传递给dispatch_after函数的dispatch_time_t类型的值。 dispatch_time_t getDispatchTimeByDate(NSDate *date) { NSTimeInterval interval; double second, subsecond; struct timespec time; dispatch_time_t millestone; interval = [date timeIntervalSince1970]; subsecond = modf(interval, &second); time.tv_sec = second; time.tv_nsec = subsecond *NSEC_PER_SEC; millestone = dispatch_walltime(&time, 0); return millestone; }