博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS-GCD多线程编程详解1
阅读量:5286 次
发布时间:2019-06-14

本文共 5852 字,大约阅读时间需要 19 分钟。

文明看博转载是对自己的尊重也是对学者的鼓励,欢迎讨论

iOS-GCD多线程编程详解

一.前言

前面的多线程编程中分别讲到NSThread和NSOperation的多线程编程,本张主要是讲述GCD的编程,GCD的多线程编程是基于BLock或者函数包裹多线程任务,由系统管理线程实现的,因此其低耦合,容易使用,又是基于C语言实现,运行速度快,是官方推荐的多线程实现的首先方案,至于个人什么顺手就用什么。

二.GCD多线程使用说明

在多线程编程中,首先要考虑的问题是多线程任务写在什么地方,同步还是异步,是在主线程中执行还是在子线程中执行,多线程任务的依赖关系,执行的先后顺序,是自己创建线程还是系统的线程承载线程任务的执行,是自己管理线程还是系统管理,对于GCD而言,多线程任务通过Block或者函数来包含多线程任务,它的依赖和执行顺序有特定的GCD函数,它的任务承载线程是有系统生成和管理,所以用户只需要关心多线程任务是使用block还是函数包裹,是使用同步还是异步,是在主线程上执行还是在子线程上执行。

1.dispathc_sync:

该函数的作用是提交一个block到指定的dispatch_queue中,直到block执行结束返回,在主线程中使用该函数就会造成UI卡住:

note:下面这段代码是在主线程中调用

NSLog(@"before dispatch_sync");				//主线程中调用    dispatch_sync(dispatch_get_main_queue(), ^{        dispatch_async(dispatch_get_main_queue(), ^{            NSLog(@"hello world");	//这条语句没有被执行        });    });
运行结果:

2015-01-03 17:45:58.213 GCDTest[1750:140657] before dispatch_sync(还有就是界面卡死了,因为形成了死锁)

note:下面的这段代码是在非主线程中调用:

@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    [NSThread detachNewThreadSelector:@selector(netThread:) toTarget:self withObject:@"new thread"];  //子线程分支    NSLog(@"hello world main");    }-(void)netThread:(id)sender{    NSLog(@"before dispatch_sync");    dispatch_sync(dispatch_get_main_queue(), ^{			//相当于在主线程中调用dispatch_sync        dispatch_sync(dispatch_get_main_queue(), ^{            NSLog(@"hello world subThread");	//从结果中看出这条语句没有被运行        });    });}@end
运行结果:

2015-01-04 17:37:04.426 GCDTest[1869:155469] before dispatch_sync(屏幕卡死)

2015-01-04 17:37:04.426 GCDTest[1869:155423] hello world main

所以在使用disatich_sync时不要在UI线程使用。

相似函数:

dispatch_sync_f:该函数提交的是一个函数任务,相当于dispatch_sync:提交block,说白了把提交的function相当于block,有兴趣的可以看我其中的一篇BLock揭秘,了解函数和block的一些映射个人思想。

dispatch_async_f(dispatch_get_main_queue(), nil, fun_my);    }static void fun_my(void *hel){    NSLog(@"function");}
运行结果:

2015-01-04 00:53:48.894 GCDTest[2010:161173] function   

在主线程中使用的dispatch_sync(dispatch_get_main_queue,^{})形成死锁图解:

dispatch_async(dispatch_get_main_queue(), ^{        NSLog(@"我是异步的block1,我被装在dispatch_get_main_queue中");    });        NSLog(@"我是主线程,我的源代码位置被写在block1的后面");
运行结果:

2015-01-04 22:37:31.821 GCDTest[713:28383] 我是主线程,我的源代码位置被写在block1的后面

2015-01-04 22:37:31.836 GCDTest[713:28383] 我是异步的block1,我被装在dispatch_get_main_queue

图解分析:

三.各个GCD函数使用详解

通过上一节的简单使用,我们可以把GCD分解为线程任务包装:block,function,线程任务的容器:dispatch_queue(序列类型和并发类型),同步和异步(重点是异步的实现);block可以参考,function就是一般的函数,同步和异步就是同步执行和异步执行,下面通过代码来了解block的容器-------dispatch_queue.

1.dispatch_global_queue

dispatch_group_t group2 = dispatch_group_create();    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{        NSLog(@"*block1 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{        NSLog(@"*block2 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{        NSLog(@"*block3 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{        NSLog(@"*block4 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{        NSLog(@"*block5 运行在线程%@",[NSThread currentThread]);    });
运行结果:

1:

2015-01-04 23:04:37.273 GCDTest[850:36850] *block2 运行在线程<NSThread: 0x7fc2d9c6e350>{number = 5, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36848] *block3 运行在线程<NSThread: 0x7fc2d9c6b200>{number = 3, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36849] *block4 运行在线程<NSThread: 0x7fc2d9f269a0>{number = 4, name = (null)}

2015-01-04 23:04:37.274 GCDTest[850:36854] *block5 运行在线程<NSThread: 0x7fc2d9c6d180>{number = 6, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36847] *block1 运行在线程<NSThread: 0x7fc2d9d1ce30>{number = 2, name = (null)}

2:

2015-01-04 23:07:09.728 GCDTest[858:37701] *block2 运行在线程<NSThread: 0x7fc569406f40>{number = 4, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37700] *block3 运行在线程<NSThread: 0x7fc56940da90>{number = 5, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37698] *block1 运行在线程<NSThread: 0x7fc5694182a0>{number = 2, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37699] *block4 运行在线程<NSThread: 0x7fc56952c740>{number = 3, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37704] *block5 运行在线程<NSThread: 0x7fc569713820>{number = 6, name = (null)}

。。。

运行结果每次都不同,所在的运行线程也不同,所以dispatch_global_queue是并行的系统维护的线程依次冲队列中取出block执行

2.dispatch_main_queue

dispatch_group_t group = dispatch_group_create();    dispatch_group_async(group, dispatch_get_main_queue(), ^{        NSLog(@"block1 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group, dispatch_get_main_queue(), ^{        NSLog(@"block2 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group, dispatch_get_main_queue(), ^{        NSLog(@"block3 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group, dispatch_get_main_queue(), ^{        NSLog(@"block4 运行在线程%@",[NSThread currentThread]);    });        dispatch_group_async(group, dispatch_get_main_queue(), ^{        NSLog(@"block5 运行在线程%@",[NSThread currentThread]);    });
运行结果:

2015-01-04 23:07:09.762 GCDTest[858:37660] block1 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block2 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block3 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block4 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.763 GCDTest[858:37660] block5 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

运行结果每次都是一致的,说明dispatch_main_queue是根据其加入顺序执行的执行的线程为主线程;

所以顺序队列和并行队列的对比图如下:

小结:这篇博文主要说了关于顺序队列和并行队列的block容器的特性,后面将会陆续的对GCD的多线程编程有详细的使用。

引用或者转载请注明出处,是对自己的尊重也是对学者的鼓励。

转载于:https://www.cnblogs.com/fanyiyao-980404514/p/4207421.html

你可能感兴趣的文章
统计Xcode项目代码行数
查看>>
认识 service worker
查看>>
第五次团队作业:项目展示
查看>>
WIN10更新后,应用报“不能在此路径中使用此配置节。如果在父级别上锁定了该节,便会出现这种情况”...
查看>>
C#面向对象(二):封装和继承
查看>>
range()函数
查看>>
cs20_3-3
查看>>
codevs1074 食物链
查看>>
少量标签下的模型
查看>>
17.python购物车程序作业
查看>>
lightoj 1027【数学概率】
查看>>
Apparmor——Linux内核中的强制访问控制系统
查看>>
HOJ-1005 Fast Food(动态规划)
查看>>
jQuery 杂项方法
查看>>
FasfDFS整合Java实现文件上传下载
查看>>
用Hadoop构建电影推荐系统
查看>>
[读码时间] 弹出层效果
查看>>
UVAL 4728 Squares(旋转卡壳)
查看>>
Ordered Fractions usaco
查看>>
web框架的概念
查看>>