GCD提供很多超越传统多线程编程的优势:
易用: GCD比之thread跟简单易用。由于GCD基于work unit而非像thread那样基于运算,所以GCD可以控制诸如等待任务结束、监视文件描述符、周期执行代码以及工作挂起等任务。基于block的血统导致它能极为简单得在不同代码作用域之间传递上下文。
效率: GCD被实现得如此轻量和优雅,使得它在很多地方比之专门创建消耗资源的线程更实用且快速。这关系到易用性:导致GCD易用的原因有一部分在于你可以不用担心太多的效率问题而仅仅使用它就行了。
性能: GCD自动根据系统负载来增减线程数量,这就减少了上下文切换以及增加了计算效率。
Dispatch Queues
GCD的基本概念就是dispatch queue。dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的。并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行,串行队列同一时间只执行单一任务。
GCD中有三种队列类型:
The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
用户队列: 用户队列 (GCD并不这样称呼这种队列,但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列)是用函数 dispatch_queue_create创建的队列.这些队列是串行的。正因为如此,它们可以用来完成同步机制,有点像传统线程中的mutex。
-(void)createQueue
{
//串行队列,它们可以用来完成同步机制
dispatch_queue_t mainQueue =dispatch_get_main_queue();//主队列
dispatch_queue_t serialQueue =dispatch_queue_create("com.dikangmedicine.dongu",NULL);//用户队列
//全局队列是并发队列,并由整个进程共享
dispatch_queue_t parallelQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
NSLog(@"%@ %@ %@",mainQueue,serialQueue,parallelQueue);
}
#pragma mark 测试在 主线程上面更新界面,分别使用dispatch_async和dispatch_async_f 2种风格实现
//直接执行与UI相关的任务,必须在主线程执行,有 2种向主队列分派任务的方法,两者都是异步的,即使在任务没有执行的时候也让你的程序继续
//Dispatch_sync 方法不能在主队列中调用,因为无限期的阻止线程并会导致你的应用死锁。所有通过 GCD 提交到主队列 的任务必须异步提交。
//在另一个队列中访问主线程并运行代码:dispatch_sync(dispatch_get_main_queue(),queue);
-(void)testPerformUIRelatedTaskWithGCD
{
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc]initWithTitle:@"dh"
message:@"mesd"
delegate:nil
cancelButtonTitle:@"取消"
otherButtonTitles:nil]show];
});
}
-(void)testPerformUIRelatedTaskWithGCDInC
{
AlertViewData *context = (AlertViewData *)malloc(sizeof(AlertViewData));
if (context != NULL)
{
context->title = "dh";
context->message = "mesd";
context->cancleBtnTitle = "取消";
}
dispatch_async_f(dispatch_get_main_queue(),
(void *)context,
displayAlertView);
}
void displayAlertView(void *param)
{
AlertViewData *alertData = (AlertViewData *)param;
[[[UIAlertView alloc]initWithTitle:format(alertData->title) message:format(alertData->message) delegate:nil cancelButtonTitle:format(alertData->cancleBtnTitle) otherButtonTitles:nil] show];
}
#pragma mark 同步执行与UI无关的任务
-(void)testSyncNoneUIRelated
{
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"%@",[NSThread currentThread]);
for (int i=0; i<100; i++) {
NSLog(@"%d",i);
}
});
}
-(void)testSyncNoneUIRelatedWithC
{
FromAndToNum *fromAndToNum = (FromAndToNum *)malloc(sizeof(fromAndToNum));
if (fromAndToNum!=NULL) {
fromAndToNum->fromNum = 11;
fromAndToNum->toNum = 21;
}
dispatch_sync_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), fromAndToNum, printFrom1To100);
}
void printFrom1To100(void *param)
{
FromAndToNum *context = (FromAndToNum *)param;
for (int i=context->fromNum; i<=context->toNum; i++) {
NSLog(@"currentThread: %@----%d",[NSThread currentThread],i);
}
}
#pragma mark 异步执行与UI无关的任务
-(void)testAsyncNoneUIRelated
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"%@",[NSThread currentThread]);
for (int i=0; i<100; i++) {
NSLog(@"%d",i);
}
});
}
-(void)testAsyncNoneUIRelatedWithC
{
FromAndToNum *fromAndToNum = (FromAndToNum *)malloc(sizeof(fromAndToNum));
if (fromAndToNum!=NULL) {
fromAndToNum->fromNum = 11;
fromAndToNum->toNum = 21;
}
dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), fromAndToNum, printFrom1To100);
}
//测试下载一张图片并将它作为当前页面背景,在另一个队列中访问主线程并运行代码:dispatch_sync(dispatch_get_main_queue(),queue);
-(void)downloadImageAndSetBackground
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
__block UIImage *image = nil;
dispatch_sync(queue, ^{
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://images.apple.com/mobileme/features/images/ipad_findyouripad_20100518.jpg"]];
NSError *downError = nil;
NSData *downloadData = [NSURLConnection sendSynchronousRequest:req
returningResponse:nil
error:&downError];
if (downError==nil&&downloadData!=nil) {
image = [UIImage imageWithData:downloadData];
}
});
dispatch_sync(dispatch_get_main_queue(), ^{
if (image!=nil) {
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
}
});
});
}
//在磁盘创建一个保存100个随机数字的数组,读到内存,并按降序排列
-(void)createArrAndSaveToDisk
{
NSString *arrSavePath = [NSString stringWithFormat:@"%@/test",NSTemporaryDirectory()];
if (![[NSFileManager defaultManager] fileExistsAtPath:arrSavePath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:arrSavePath
withIntermediateDirectories:YES
attributes:nil
error:nil];
}
NSMutableArray *arr = [NSMutableArray array];
for (int i=0; i<100; i++) {
NSNumber *num = [NSNumber numberWithInt:(arc4random()%(RAND_MAX+1))];
[arr addObject:num];
}
[arr writeToFile:[NSString stringWithFormat:@"%@/list.txt",arrSavePath] atomically:YES];
}
-(void)sortArrDesc
{
__block ViewController *viewCtr = self;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
[viewCtr createArrAndSaveToDisk];
});
dispatch_sync(queue, ^{
NSMutableArray *arr = [NSMutableArray arrayWithContentsOfFile:[NSString stringWithFormat:@"%@/test/list.txt",NSTemporaryDirectory()]];
[arr sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSNumber *number1 = (NSNumber *)obj1;
NSNumber *number2 = (NSNumber *)obj2;
return [number2 compare:number1];
}];
NSLog(@"%@",[arr description]);
});
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"可以在这里执行UI相关的更新任务");
});
});
}
//测试各种queue的优先级别
//结论:各层次的异步队列会另开线程执行,后面的任务无需等待。同步队列会执行完成之后才执行之后的任务。
-(void)testQueueExecuteOrder
{
__block ViewController *viewCtr = self;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_async(queue, ^{
[viewCtr longTimeTask];
NSLog(@"1...%@",[NSDate date]);
});
dispatch_sync(queue, ^{
NSLog(@"2....%@",[NSDate date]);
});
dispatch_sync(queue, ^{
NSLog(@"3....%@",[NSDate date]);
});
});
dispatch_sync(queue, ^{
NSLog(@"4....%@",[NSDate date]);
});
}
//压力运算任务
-(void)longTimeTask
{ int t = 0;
for (int i=0; i<1000000000; i++) {
t +=i;
}
}
#pragma mark 利用 GCD 延時後執行任務
-(void)testDelayBlock
{
NSLog(@"%@",[NSDate date]);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, queue, ^(void){
NSLog(@"haha");
NSLog(@"%@",[NSDate date]);
});
}
-(void)testDelayBlockWithC
{
FromAndToNum *fromAndToNum = (FromAndToNum *)malloc(sizeof(fromAndToNum));
if (fromAndToNum!=NULL) {
fromAndToNum->fromNum = 1;
fromAndToNum->toNum = 50;
}
dispatch_after_f(DISPATCH_TIME_NOW, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),fromAndToNum,printFrom1To100);
}
#pragma mark 在GCD上一个任务最多执行一次
-(void)testDispatchOnce
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_async(queue, ^{
NSLog(@"2");
});
});
dispatch_once(&onceToken, ^{
dispatch_async(queue, ^{
NSLog(@"3");
});
});
}
#pragma mark 用GCD对任务进行分组
//组内部任务测试为同按添加顺序这个执行
-(void)testDispatchGroup
{
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
__block ViewController *viewCtr = self;
dispatch_group_async(taskGroup, mainQueue, ^{
NSLog(@"1");
});
dispatch_group_async(taskGroup, mainQueue, ^{
[viewCtr longTimeTask];
NSLog(@"ddd");
});
dispatch_group_async(taskGroup, mainQueue, ^{
NSLog(@"3");
});
dispatch_group_notify(taskGroup, mainQueue, ^{
NSLog(@"complete");
});
}
#pragma mark 使用GCD构建自己的分派队列
//串行分派队列 ,串行调度队列按照先入先出 (FIFO)的原则运行它们的任务。串行队列上的异步任务在主线程以外的线程上执行,同步任务在当前线程执行
// dispatch_queue_create 函数创建串行队列。这个函数的第一个参数是 C 字符串(char *),它将唯一标识系统中的串行队列,是一个全系统标识符,因此建议使用反向 DNS 格式的标识符,避免和其它APP使用的标示符相同,产生未知结果。
-(void)testDispatchQueueCreate
{
dispatch_queue_t firstQueue = dispatch_queue_create("com.dynastech.GCD.serialQueue", 0);
dispatch_async(firstQueue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"%d",i);
}
});
dispatch_async(firstQueue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"%d",i);
}
});
dispatch_async(firstQueue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"%d",i);
}
});
}