今天是年前最后一天上班,偷了点懒(忏悔中…)。尽管明天就见到爸妈,尽管明天就能喝到排骨藕汤(¯﹃¯),但是还是高兴不起来。发现还是找不准自己的位置,心情总是波动起伏不定。有时候因为一句话、一件事,搞得自己魂不守舍,就像杜甫和李清照的诗句一样,完全是两个极端,想趁着过年这段时间,放下心中的包袱,赶紧调整自己,还是写博客能让心中平静一些。
漫卷诗书喜欲狂,白日放歌须纵酒。
感月吟风多少事,如今老去无成,谁怜憔悴更凋零,试灯无意思,踏雪没心情。
今天讲讲GCD的使用。
首先看队列,队列可以分为并行队列和串行队列,队列可以分为同步执行和异步执行。
同步执行可以分为串行队列的同步执行和并行队列的同步执行,异步执行又可以分为串行队列的异步执行和并行队列的异步执行。
下面会说明串行队列与并行队列的同步执行,串行队列与并行队列的异步执行。并且会说明同步执行和异步执行的区别。先提取一下公共方法。
#pragma mark - 返回当前线程
- (NSThread *)getCurrentThread
{
return [NSThread currentThread];
}
#pragma mark - 模拟线程耗时
- (void)currentThreadSleep:(NSTimeInterval)timer
{
[NSThread sleepForTimeInterval:timer];
}
#pragma mark - 获取主队列
- (dispatch_queue_t)getMainQueue
{
return dispatch_get_main_queue();
}
#pragma mark - 获取全局队列
- (dispatch_queue_t)getGlobalQueue
{
//默认优先级DISPATCH_QUEUE_PRIORITY_DEFAULT
return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
先看看串行队列(Serial Queue)与 并行队列(Concurrent Queue)的区别。这两个队列都遵循先入先出原则,不同的是串行队列要等前面的任务出队列执行完成后,下个任务才能出队列执行。并行队列只要前面的任务出队列了,还有空余线程,不管前面的任务是否执行完,下一个任务都可以出队列。
#pragma mark - 创建并行队列 string 并行队列的标记
- (dispatch_queue_t)getConcurrentQueue:(char *)string
{
return dispatch_queue_create(string, DISPATCH_QUEUE_CONCURRENT);
}
#pragma mark - 创建串行队列 string 串行队列的标记
- (dispatch_queue_t)getSerialQueue:(char *)string
{
return dispatch_queue_create(string, DISPATCH_QUEUE_SERIAL);
}
一 同步执行
#pragma mark - 同步执行
- (void)sync:(dispatch_queue_t)queue
{
for (int i = 0 ; i < 3 ; i ++ )
{
dispatch_sync(queue, ^{
[self currentThreadSleep:1];
NSLog(@"当前执行线程%@",[self getCurrentThread]);
NSLog(@"执行%d",i);
});
NSLog(@"%d执行完毕",i);
}
NSLog(@"所有队列使用同步方式执行完毕");
}
- (IBAction)btn1Click:(id)sender {
NSLog(@"同步执行串行队列");
[self sync:[self getSerialQueue:"syn.serial.queue"]];
}
- (IBAction)btn2Click:(id)sender {
NSLog(@"同步执行并行队列");
[self sync:[self getConcurrentQueue:"syn.concurrent.queue"]];
}
从上面的示例可以知道,同步执行方式来执行队列不会开辟新的线程,会在当前线程中执行任务。当前线程是主线程,就会阻塞主线程,造成UI卡死的现象。在同一个线程执行,串行队列和并行队列使用同步执行的结果是一样的,都必须等到上一个任务出队列并且执行完成才能执行下个任务。
二 异步执行
#pragma mark - 异步执行
- (void)async:(dispatch_queue_t)queue
{
dispatch_queue_t serialQueue = [self getSerialQueue:"serialQueue"];
for (int i = 0 ; i < 3 ; i ++ )
{
dispatch_async(queue, ^{
[self currentThreadSleep:2];
NSThread * currentThread = [self getCurrentThread];
//同步锁
dispatch_sync(serialQueue, ^{
NSLog(@"sleep的线程%@",[self getCurrentThread]);
NSLog(@"当前输出内容的线程%@",currentThread);
NSLog(@"执行%d:%@",i,queue);
});
});
NSLog(@"%d执行完毕",i);
}
NSLog(@"使用异步方式添加队列");
}
- (IBAction)btn3Click:(id)sender {
NSLog(@"异步执行串行队列");
[self async:[self getSerialQueue:"asyn.serial.queue"]];
//dispatch_saync 开辟了新线程number = 3来执行block中的内容,block外的东西依旧在之前的线程执行
}
- (IBAction)btn4Click:(id)sender {
NSLog(@"异步执行并行队列");
[self async:[self getConcurrentQueue:"asyn.concurrent.queue"]];
}
异步执行同样也分为串行队列的异步执行和并行队列的异步执行。dispatch_async和dispatch_sync的区别是它会开辟新的线程,不会阻塞当前线程。异步队列的特点是只要要可用的线程,任务就会出队列执行,而不关心之前出队列的任务(block)是否执行完毕。
三 延时执行
GCD中使用dispatch_after()函数来延时执行队列中的任务,dispatch_after()是异步执行队列中的任务的,也就是说使用dispatch_after()不会阻塞当前任务。等到延时时间到了以后就会开辟一个新的线程然后执行队列中的任务。
#pragma mark - 延时操作
- (void)deferPerform:(double)time
{
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (time * NSEC_PER_SEC));
dispatch_after(delayTime, [self getGlobalQueue], ^{
NSLog(@"执行线程:%@ \n 延迟%f秒执行 ",[self getCurrentThread],time);
});
}
四 队列的优先级
队列有优先级,分为4个级别 High > Default > Low > Background。上面在获取全局队列时可以执行队列的优先级,并且可以使用dispatch_set_target_queue()函数将一个队列的优先级赋值给另一个队列。
#pragma mark - 1为全局队列指定优先级
- (void)globalQueuePriority
{
//高 > 默认 > 低 > 后台
dispatch_queue_t queueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t queueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t queueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
//一般会按照这个优先级执行,但是不是绝对的,一般使用DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(queueLow, ^{
NSLog(@"Low:%@",[self getCurrentThread]);
});
dispatch_async(queueBackground, ^{
NSLog(@"Background:%@",[self getCurrentThread]);
});
dispatch_async(queueDefault, ^{
NSLog(@"Default:%@",[self getCurrentThread]);
});
dispatch_async(queueHigh, ^{
NSLog(@"High:%@",[self getCurrentThread]);
});
}
#pragma mark - 2自创的队列指定优先级
- (void)setPriority
{
//将queueHigh的优先级赋值给queue队列
dispatch_queue_t queue = [self getSerialQueue:"serialQueue"];
dispatch_queue_t queueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(queue, queueHigh);
}
还有GCD比较高级的用法没有时间讲,下次有时间再说。明天还要赶早火车。最后送上那些花儿-朴树,晚安~