//
// ViewController.m
// GCD中得常用方法
//
//
#
import
"ViewController.h"
@
interface
ViewController ()
@end
@implementation ViewController
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self doSerialDiapatchQueue];
}
-(
void
)doSerialDiapatchQueue
{
NSLog(@
"=====Serial Diapatch Queue 串行队列,每一个Queue启动一个线程====="
);
//创建串行队列
dispatch_queue_t serialDiapatchQueue=dispatch_queue_create(
"com.test.queue"
, NULL);
//使用队列
dispatch_async(serialDiapatchQueue, ^{
NSLog(@
"1"
);
});
dispatch_async(serialDiapatchQueue, ^{
sleep(
2
);
NSLog(@
"2"
);
});
dispatch_async(serialDiapatchQueue, ^{
sleep(
1
);
NSLog(@
"3"
);
});
// ios 6 之后 ARC自动管理 dispatch_release(serialDiapatchQueue);
}
-(
void
)doConcurrentDiapatchQueue
{
NSLog(@
"=====Concurrent Diapatch Queue 并发队列,一个队列触发多个线程====="
);
//创建并发队列
dispatch_queue_t concurrentDiapatchQueue=dispatch_queue_create(
"com.test.queue"
, DISPATCH_QUEUE_CONCURRENT);
//使用队列
dispatch_async(concurrentDiapatchQueue, ^{
NSLog(@
"1"
);
});
dispatch_async(concurrentDiapatchQueue, ^{
sleep(
2
);
NSLog(@
"2"
);
});
dispatch_async(concurrentDiapatchQueue, ^{
sleep(
1
);
NSLog(@
"3"
);
});
// ios 6 之后 ARC自动管理 dispatch_release(serialDiapatchQueue);
}
-(
void
)doGlobalQueueAndMainQueue
{
NSLog(@
"=====Main Diapatch Queue/Global Diapatch Queue GCD中最常用的多线程操作====="
);
//GlobalQueue其实就是系统创建的ConcurrentDiapatchQueue
//MainQueue其实就是系统创建的位于主线程的SerialDiapatchQueue
//MainQueue队列中插入会放在本次Runloop的最后
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@
"5"
);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
0
), ^{
NSLog(@
"4"
);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,
0
), ^{
NSLog(@
"3"
);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
NSLog(@
"2"
);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,
0
), ^{
NSLog(@
"1"
);
});
NSLog(@
"=====常用方式====="
);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,
0
), ^{
NSLog(@
"6"
);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@
"7"
);
});
});
}
-(
void
)doDispatchSetTargetQueue
{
NSLog(@
"=====dispatch_set_target_queue 用于改变手动创建Queue的优先级====="
);
dispatch_queue_t serialDiapatchQueue=dispatch_queue_create(
"com.test.queue"
, NULL);
dispatch_queue_t dispatchgetglobalqueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,
0
);
dispatch_set_target_queue(serialDiapatchQueue, dispatchgetglobalqueue);
dispatch_async(serialDiapatchQueue, ^{
NSLog(@
"2"
);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
NSLog(@
"1"
);
});
//简单的理解为我们自己创建的queue其实是位于global_queue中执行,所以改变global_queue的优先级,也就改变了我们自己所创建的queue的优先级。
//同时,我们用这个方法可以做到用队列管理子队列
}
-(
void
)doDispatchAfter
{
NSLog(@
"=====dispatch_after 延迟到指定时间之后执行====="
);
NSLog(@
"小破孩-波波"
);
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
){
NSLog(@
"小破孩-波波"
);
});
//在不挂起线程和不sleep的情况下,在2秒后插入到主线程的RunLoop中,但是之前说了dispatch_get_main_queue是插入到本次RunLoop的最后,所以真正执行会大于2秒。
//test: 2014-04-15 16:05:39.870 GCD中得常用方法[2455:70b] 小破孩-波波
// 2014-04-15 16:05:41.871 GCD中得常用方法[2455:70b] 小破孩-波波
// 多了0.001秒,说明这个函数中Runloop的周期就是0.001秒
}
-(
void
)doDispatchGroup
{
NSLog(@
"=====Dispatch Group 队列组====="
);
//用户监督组里面队列的完成
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
);
dispatch_group_t group=dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@
"0"
);});
dispatch_group_async(group, queue, ^{NSLog(@
"1"
);});
dispatch_group_async(group, queue, ^{NSLog(@
"3"
);});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@
"down"
);});
//之前说了用dispatch_set_target_queue把子队列放到一个串行队列中,如果子队列是串行队列也可以达到一样的效果,但是并发队列的管理就变得复杂了,故引入Group的方法。
//dispatch_group_wait(group, DISPATCH_TIME_NOW) 这个方法在每个RunLoop的周期中都会返回值,用来检查是否执行完成。
// ios 6 之后 ARC自动管理 dispatch_release(group);
}
- (
void
)didReceiveMemoryWarning
{
[
super
didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
-(
void
)doDispatchBarrierAsync
{
NSLog(@
"=====Dispatch Barrier Async 在并发对联中单独执行一个任务====="
);
//创建并发队列
dispatch_queue_t concurrentDiapatchQueue=dispatch_queue_create(
"com.test.queue"
, DISPATCH_QUEUE_CONCURRENT);
//此方法用于并发队列时打断其他线程,只执行队列中一个任务。
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"0"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"1"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"2"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"3"
);});
dispatch_barrier_async(concurrentDiapatchQueue, ^{sleep(
1
); NSLog(@
"4"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"5"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"6"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"7"
);});
dispatch_async(concurrentDiapatchQueue, ^{NSLog(@
"8"
);});
// ios 6 之后 ARC自动管理 dispatch_release(concurrentDiapatchQueue);
//2014-04-18 11:25:09.142 GCD中得常用方法[15546:3007] 1
//2014-04-18 11:25:09.142 GCD中得常用方法[15546:3503] 2
//2014-04-18 11:25:09.142 GCD中得常用方法[15546:1303] 0
//2014-04-18 11:25:09.142 GCD中得常用方法[15546:3603] 3
//2014-04-18 11:25:10.145 GCD中得常用方法[15546:3603] 4
//2014-04-18 11:25:10.146 GCD中得常用方法[15546:3603] 5
//2014-04-18 11:25:10.146 GCD中得常用方法[15546:1303] 6
//2014-04-18 11:25:10.146 GCD中得常用方法[15546:3007] 7
//2014-04-18 11:25:10.146 GCD中得常用方法[15546:3503] 8
//看打印结果,我们发现,在执行dispatch_barrier_async的时候5、6、7、8也没有并发执行,而是等4执行结束之后,才继续并发执行。
//我们可以设想一个使用场景,对一个数组删除和读取的时候,如果正在读得瞬间删除了一条数据,导致下标改变,那就有可能出问题,甚至crash,这时候这个操作就能避免此类问题出现。
}
-(
void
)doDispatchSync
{
NSLog(@
"=====Dispatch Sync 同步执行====="
);
//切记,千万别在执行Dispatch Sync方法的队列中调用自身队列,否则,死锁。
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
);
dispatch_sync(queue, ^{sleep(
1
);NSLog(@
"1"
);});
dispatch_sync(queue, ^{sleep(
1
);NSLog(@
"2"
);});
dispatch_sync(queue, ^{sleep(
1
);NSLog(@
"3"
);});
NSLog(@
"4"
);
//2014-04-18 11:47:20.512 GCD中得常用方法[15673:60b] 1
//2014-04-18 11:47:21.513 GCD中得常用方法[15673:60b] 2
//2014-04-18 11:47:22.514 GCD中得常用方法[15673:60b] 3
//2014-04-18 11:47:22.515 GCD中得常用方法[15673:60b] 4
/*从线程编号中我们发现,同步方法没有去开新的线程,而是在当前线程中执行队列,会有人问,上文说dispatch_get_global_queue不是并发队列,
并发队列不是应该会在开启多个线程吗?,这个前提是用异步方法。GCD其实是弱化了线程的管理,强化了队列管理,这使我们理解变得比较形象。*/
}
-(
void
)doDispatchAsyncF
{
NSLog(@
"=====dispatch_async_f C方法调用异步====="
);
//应“天意”要求,这里给大家用一次“dispatch_async_f”方法,个人喜欢用block;
// dispatch_async_f(queue, void *context, dispatch_function_t work)
// queue:指定执行该work的队列,这个和用block一样
// void *context:所使用的 application-defined(应用程序范围内有效的,也就是全局的)级别的参数。这是个C语法,void * 是一个无类型指针。也就是说,用它可以指向任何内存数据。
// work:在指定队列(queue 参数)中要执行的方法。在该方法中,第一个参数所指代的数据,也就是dispatch_async_f方法所使用的第二个参数(void *context)所指带的数据。
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
);
int
a =
1
;
dispatch_async_f(queue, &a, logNum);
//如果用block就变得非常容易
int
i=
2
;
dispatch_async(queue,^{NSLog(@
"%i"
,i);});
}
void
logNum(
void
*a)
{
NSLog(@
"%i"
,(
int
)*(
int
*)a);
}
-(
void
)doDispatchApply
{
NSLog(@
"=====dispatch_async====="
);
//此方法可用于异步遍历,提高遍历的效率。
NSArray *array=[[NSArray alloc]initWithObjects:@
"0"
,@
"1"
,@
"2"
,@
"3"
,@
"4"
,@
"5"
,@
"6"
, nil];
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
);
dispatch_async(queue, ^{
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@
"%zu=%@"
,index,[array objectAtIndex:index]);
});
});
}
-(
void
)doSuspendResunme
{
NSLog(@
"=====dispatch_suspend/dispatch_resume 挂起/恢复====="
);
dispatch_queue_t concurrentDiapatchQueue=dispatch_queue_create(
"com.test.queue"
, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentDiapatchQueue, ^{
for
(
int
i=
0
; i<
100
; i++)
{
NSLog(@
"%i"
,i);
if
(i==
50
)
{
NSLog(@
"-----------------------------------"
);
dispatch_suspend(concurrentDiapatchQueue);
sleep(
3
);
dispatch_resume(concurrentDiapatchQueue);
}
}
});
//此demo模拟当遇到符合某个特定值的时候挂起线程,然后等处理完之后恢复线程。
}
-(
void
)doSemaphore
{
NSLog(@
"=====dispatch_semaphore 信号量====="
);
//dispatch_semaphore_signal 信号量+1;
//dispatch_semaphore_wait 信号量-1, 当变为0后如果是DISPATCH_TIME_FOREVER,则永远等待;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(
10
);
//为了让一次输出10个,初始信号量为10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
);
for
(
int
i =
0
; i <
100
; i++)
{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//每进来1次,信号量-1;进来10次后就一直hold住,直到信号量大于0;
dispatch_async(queue, ^{
NSLog(@
"%i"
,i);
sleep(
2
);
dispatch_semaphore_signal(semaphore);
//由于这里只是log,所以处理速度非常快,我就模拟2秒后信号量+1;
});
}
//IOS 6 ARC自动管理 dispatch_release(semaphore);
//这个demo的使用场景是为了防止并发数过多导致系统资源吃紧。
//在这里不得不提到并发的真实工作原理,以单核CPU做并发为例,一个CPU永远只能干一件事情,那如何同时处理多个事件呢,聪明的内核工程师让CPU干第一件事情,一定时间后停下来,存取进度,干第二件事情以此类推,所以如果开启非常多的线程,单核CPU会变得非常吃力,即使多核CPU,核心数也是有限的,所以合理分配线程,变得至关重要。
//讲到这也不得不提如何高效的发挥多核CPU的性能,如果让一个核心模拟传很多线程,经常干一半放下干另一件事情,那效率也会变低,所以我们要合理安排,将单一任务或者一组相关任务并发至全局队列中运算或者将多个不相关的任务或者关联不紧密的任务并发至用户队列中运算。
}
-(
void
)doDispatchOnce
{
NSLog(@
"=====dispatch_once====="
);
//此方法都用于单例。
static
dispatch_once_t once;
dispatch_once(&once,^{
NSLog(@
"只执行1次"
);
});
}
转载请注明:苏demo的别样人生 » GCD demo