iOS多线程拾贝------操作巨人编程
多线程
基本
- 实现方案:pthread - NSThread - GCD - NSOperation
- Pthread
- 多平台,可移植
- c语言,要程序员管理生命周期
- 创建
//这里已经开启了多线程,直接在这里调用子线程想要调用的代码 void * run(void *pramga) { NSLog(@"-------"); return NULL; } - (IBAction)btnClick:(id)sender { pthread_t pthread; pthread_create(&pthread, NULL, run, NULL); }
- NSThread
- 面向对象,简单实用
- 创建
//隐式创建并启动线程 [NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:@"etund"]; 或者 //创建线程并且启动线程 [self performSelectorInBackground:@selector(threadRun:) withObject:@"etund"]; 或者 //上述两个优点是可以快速的创建并启动线程,方便快捷,但是不能对线程进行多余属性的设置,而下面一种方法就可以对线程实例属性的设置,但是要记得要手动开启线程。 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"etund"]; [thread start];
- Pthread
GCD
- 听说全称是叫“牛逼的中枢调度器”,但是我还是喜欢叫大中央调度
- 纯C语言,有很多强大的函数
- 优势:(纯属板书)
- GCD是苹果公司为多核的并行运算提出的解决方案
- GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
- 核心:清楚什么是任务,队列
- 串行与并行不能决定是否要开启新县城
- 并行表明具有创建新线程的能力,但不一定创建新线程
- 常用GCD内容
- 串行同步(并行同步/全局队列同步),由于串行同步,并行同步,以及全局队列同步都是不创建线程按顺序执行,所以归为一类来讲。(不开任何子线程,在主线程中执行)
//串行 dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL); //并行 //dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@----2",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"%@----3",[NSThread currentThread]); }); 运行结果 2015-07-08 19:09:39.611 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}---1 2015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----2 2015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----3
- 串行异步 (开启一个子线程,在子线程中执行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@---3",[NSThread currentThread]); }); /*运行结果 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---1 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---2 2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---3 */
- 并行异步(全局队列异步)虽然线程的执行顺序不一样,但是任务从队列里面拿出来放进线程的顺序是按照先进先出的这是根本,基础。(有几个任务,开启几个子线程,在各自的子线程中执行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"%@---3",[NSThread currentThread]); }); // 虽然线程的执行顺序不一样,但是任务从队列里面拿出来放进线程的顺序是按照先进先出 /* *2015-07-08 19:27:46.060 Pthread-多平台[68694:318231] <NSThread: 0x7f9a89c126b0>{number = 4, name = (null)}---2 2015-07-08 19:27:46.060 Pthread-多平台[68694:318230] <NSThread: 0x7f9a8c211400>{number = 5, name = (null)}---3 2015-07-08 19:27:46.060 Pthread-多平台[68694:318171] <NSThread: 0x7f9a89f9efe0>{number = 3, name = (null)}---1 */
- 主队列异步,不开任何子线程,在主线程中运行,也对应了那句话,异步队列只是具有开启子线程的能力,但是不一定开子线程。
// 主队列异步(不开线程) dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---3",[NSThread currentThread]); ; }); /* 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---1 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---2 2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---3 */
- 主队列同步
- (void)gcdTest_2_4{ NSLog(@"=-=-=-"); // 主队列同步(阻塞) dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---3",[NSThread currentThread]); }); NSLog(@"=-=-=-"); }
------------至此,基本GCD队列已经被差不多就这样了,下面来一下有趣的用法
- GCD队列组,有这么一个需求,你的一个步骤要在其他步骤完成之后才能完成,也就是后续步骤要依赖于前期步骤,这是GCD队列组以及Barrier队列(栅栏队列)不失为一个好办法,
- 串行同步(并行同步/全局队列同步),由于串行同步,并行同步,以及全局队列同步都是不创建线程按顺序执行,所以归为一类来讲。(不开任何子线程,在主线程中执行)
//GCD队列组方式 // (线程组)(线程通讯) // dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 加载图片1 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; }); // 加载图片2 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; }); // 合并 dispatch_group_notify(group, queue, ^{ UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0); [self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //GCD线程之间的通信 dispatch_async(dispatch_get_main_queue(), ^{ self.myView.image = image; }); }); //栅栏dispatch_barrier方式 dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT);//创建多个线程 dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; }); dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; }); dispatch_barrier_async(queue, ^{ }); dispatch_async(queue, ^{ UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0); [self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); dispatch_async(dispatch_get_main_queue(), ^{ self.myView.image = image; }); });
- 延迟加载
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后异步执行这里的代码... });
- 快速迭代,当我们不需要注重迭代的顺序,只需要快速获得子元素的时候,GCD的快速迭代为你提供了途径
// (快速迭代) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(self.view.subviews.count, queue, ^(size_t index) { id obj = self.view.subviews[index]; NSLog(@"---%zu---%@",index,obj); }); /* 2015-07-08 22:26:39.851 Pthread-多平台[972:17366] ---0---<_UILayoutGuide: 0x7fd86b644e00; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7fd86b643ab0>> 2015-07-08 22:26:39.851 Pthread-多平台[972:17444] ---2---<UIImageView: 0x7fd86b645ba0; frame = (100 100; 100 100); clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x7fd86b643290>> 2015-07-08 22:26:39.851 Pthread-多平台[972:17435] ---1---<_UILayoutGuide: 0x7fd86b6457b0; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x7fd86b644040>> */
- once一次性代码(单例模式设计),有时候我们需要用到单例模式做一些操作例如:传值时,就会用到单例设计模式,设计单例模式的方法很多,其中最重要的是要做到线程安全,而GCD就提供了这么一个结构体来保证在创建单例过程中的线程安全
ETPerson.h + (instancetype)sharePerson; ETPerson.m @implementation ETPerson static ETPerson *_person; + (instancetype)sharePerson{ static dispatch_once_t onceDispatch; dispatch_once(&onceDispatch, ^{ _person = [[ETPerson alloc] init]; }); return _person; } + (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceDispatch; dispatch_once(&onceDispatch, ^{ _person = [super allocWithZone:zone]; }); return _person; } - (id)copyWithZone:(NSZone *)zone{ return _person; } @end 调用 // onece(单例) NSLog(@"%@----%@------%@-------%@------%@-----%@",[[ETPerson alloc] init],[[ETPerson alloc] init],[ETPerson copy],[ETPerson copy],[ETPerson sharePerson],[ETPerson sharePerson]); /*运行结果 2015-07-08 23:26:57.292 Pthread-多平台[1350:37528] <ETPerson: 0x7fc4bb4041c0>----<ETPerson: 0x7fc4bb4041c0>------ETPerson-------ETPerson------<ETPerson: 0x7fc4bb4041c0>-----<ETPerson: 0x7fc4bb4041c0> */
线程通信
- 线程之间的通信,线程的通信,在一个进程中,线程往往不是鼓励存在的,多个线程之间需要经常进行通信
- 线程间通信的体现
- 在一个线程传递数据给另外一个线程
- 在一个线程中执行完成任务后,转到另一个线程继续执行任务
- NSThread的线程通信
//这个方法是指在当前线程运行完后调到主线程里面运行 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; //这个方法是指在当前线程运行完后调用另外一个线程里面运行 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait
- GCD的线程通信,GCD的线程通信十分简单,只是在代码块里面调用代码块,直接上代码吧。
从子线程回到主线程 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行耗时的异步操作... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程,执行UI刷新操作 }); });
至此,iOS里面简单的多线程GCD以及NSThread以及PThread部分就入门了,明天更新NSOPeration。
时间: 2024-08-07 08:26:16