IOS开发入门iOS 多线程(四)GCD
白羽 2019-07-10 来源 :网络 阅读 1543 评论 0

摘要:本文将带你了解IOS开发入门iOS 多线程(四)GCD,希望本文对大家学IOS有所帮助。

    本文将带你了解IOS开发入门iOS 多线程(四)GCD,希望本文对大家学IOS有所帮助。

IOS开发入门iOS 多线程(四)GCD

GCD:Grand Central  Dispatch(GCD)  是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch  Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可以统一管理,也可执行任务,这样就比以前的线程更有效率。
   1 Dispatch Queue
   “Dispatch Queue”是什么,如其名称所示,是执行处理的等待队列。Dispatch Queue  按照追加的顺序执行处理。先进先出FIFO,first-in-first-out。
   队列类型:
   1 Serial Dispatch Queue 等待现在执行处理结束
   2 ConcurrentDispatch Queue 不等待现在执行处理结束
   比较两种Dispatch Queue。
    
  dispatch_sync(queue,block1);dispatch_sync(queue,block2);dispatch_sync(queue,block3);dispatch_sync(queue,block4);dispatch_sync(queue,block5);dispatch_sync(queue,block6);
   当queue为serial Dispatch  Queue,会先执行block1,当block1执行完毕后,接着执行block2,当block2执行完毕后,接着执行block3,如此重复。同时执行的处理数只能有一个。
    
   block1 -> block2-> block3-> block4-> block5-> block6
   当queue为Concurrent Dispatch  Queue时,首先执行block1,不管block1是否结束,都开始执行后面的block2,不管block2是否结束,都开始执行block3,如此重复循环。(同时执行的处理数量取决于当前系统的状态。)
    
   
   
   
    线程1
    线程2
    线程3
   
   
    block1
    block2
    block3
   
   
    block4
    block6
    block5
   
   
   
   
    
   创建方式
   第一种方式:dispatch_queue_create
   // 创建串行队列    DISPATCH_QUEUE_SERIAL =  NULL    dispatch_queue_t queue =  dispatch_queue_create("com.baidu.queue",  DISPATCH_QUEUE_SERIAL);
    
    
  // 1.创建一个并发队列    dispatch_queue_t queue =  dispatch_queue_create("com.baidu.queue",  DISPATCH_QUEUE_CONCURRENT);
   
   虽然Serial Dispatch Queue 和Current Dispatch  Queue将受到限制,但是使用dispatch_queue_create函数可生成人意多个Dispatch Queue。
   当生成多个Serial Dispatch Queue时,虽然在一个Serial Dispatch  Queue中同时只能执行一个追加处理,但多个Serial Dispatch Queue之间可以并行执行。
   通过dispatch_queue_create 函数生成的Dispatch Queue,在使用结束后需要释放。
    
   //释放dispatch_release(queue);
   第二种方式:获取系统标准提供的Dispatch Queue。
   Main Dispatch Queue,是在主线程中执行的Dispatch Queue,属于Serial Dispatch Queue。
    
   // 1.获得主队列dispatch_queue_t mainQueue = dispatch_get_main_queue();
   追加到Main Dispatch Queue的处理在主线程的RunLoop中执行。因此要将用户界面的更新等一些必须在主线程中执行的处理追加到Main  Dispatch Queue使用。与NSObject类的persormSelectorOnMainThread实例方法相同。
    
   GlobalDispatch Queue是ConCurrent Dispatch  Queue。所有应用程序都可以使用,没有必要通过dispatch_queue_create函数逐个生成Concurrent Dispatch  Queue。
    
   // 1.获得全局的并发队列dispatch_queue_t globalQueue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   第一个参数表示优先级。Global Dispatch Queue有4个执行优先级,分别是:
    
    #define DISPATCH_QUEUE_PRIORITY_HIGH 2#define  DISPATCH_QUEUE_PRIORITY_DEFAULT 0#define DISPATCH_QUEUE_PRIORITY_LOW  (-2)#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
   2 执行任务方式
   GCD有两种方法执行任务。
   1 同步的方式执行任务
   dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
   
   2 异步的方式执行任务
    
   dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
   同步和异步的区别
   同步:只能在当前线程中执行任务,不具备开启新线程的能力
   异步:可以在新的线程中执行任务,具备开启新线程的能力
   
   串行队列 同步函数
    
   /** * 串行队列 +  同步函数:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务 */-(void)syncSerial{    NSLog(@"syncSerial  ----- begin");    //创建串行队列  serial    dispatch_queue_t serialQueue =  dispatch_queue_create("com.vn.serial",  NULL);    dispatch_sync(serialQueue,  ^{        NSLog(@"1...sync....%@",[NSThread  currentThread]);    });    dispatch_sync(serialQueue,  ^{        NSLog(@"2...sync....%@",[NSThread  currentThread]);    });    dispatch_sync(serialQueue,  ^{        NSLog(@"3...sync....%@",[NSThread  currentThread]);    });    NSLog(@"syncSerial  ----- end");}
   打印:
    
    
  2016-10-19 15:36:43.810 GCD基本使用[9712:1396171] syncSerial -----  begin2016-10-19 15:36:43.810 GCD基本使用[9712:1396171] 1...sync....{number = 1, name = main}2016-10-19  15:36:43.811 GCD基本使用[9712:1396171] 2...sync....{number = 1, name = main}2016-10-19  15:36:43.811 GCD基本使用[9712:1396171] 3...sync....{number = 1, name = main}2016-10-19  15:36:43.811 GCD基本使用[9712:1396171] syncSerial -----  end
   
    
   串行队列 异步函数
    
   ** * 串行队列 + 异步函数  :会开启新的线程,但是任务是串行的,执行完一个任务,再执行下一个任务 */-(void)asyncSerial{    NSLog(@"asyncSerial  ----- begin");    //创建串行队列  serial    dispatch_queue_t serialQueue =  dispatch_queue_create("com.vn.serial", NULL);    dispatch_async(serialQueue,  ^{        NSLog(@"1...async....%@",[NSThread  currentThread]);    });    dispatch_async(serialQueue,  ^{        NSLog(@"2...async....%@",[NSThread  currentThread]);    });    dispatch_async(serialQueue,  ^{        NSLog(@"3...async....%@",[NSThread  currentThread]);    });    NSLog(@"asyncSerial  ----- end");}
    
   打印:
2016-10-19 15:38:55.354 GCD基本使用[9730:1397289] asyncSerial -----  begin2016-10-19 15:38:55.354 GCD基本使用[9730:1397289] asyncSerial -----  end2016-10-19 15:38:55.354 GCD基本使用[9730:1397758] 1...async....{number = 3, name = (null)}2016-10-19  15:38:55.355 GCD基本使用[9730:1397758] 2...async....{number = 3, name = (null)}2016-10-19  15:38:55.355 GCD基本使用[9730:1397758] 3...async....{number = 3, name =  (null)}
   主队列 同步函数
   /** * 主队列 + 同步函数: 死锁,不应该这样使用 */-  (void)syncMain{    NSLog(@"syncMain -----  begin");    //  1.获得主队列    dispatch_queue_t mainQueue = dispatch_get_main_queue();    dispatch_sync(mainQueue,  ^{        NSLog(@"1--syncMain---%@",  [NSThread  currentThread]);    });    NSLog(@"syncMain  ----- end");}
   只输出下面数据后就会卡死。
   syncMain ----- begin
   主队列 异步函数
    
  /** * 主队列 + 异步函数:  在主线程中执行任务,不会阻塞主线程。任务是串行的,执行完一个任务,再执行下一个任务 */-  (void)asyncMain{    NSLog(@"asyncMain -----  begin");    //  1.获得主队列    dispatch_queue_t mainQueue =  dispatch_get_main_queue();    dispatch_async(mainQueue,  ^{        NSLog(@"1--asyncMain---%@",  [NSThread  currentThread]);    });    dispatch_async(mainQueue,  ^{        NSLog(@"2--asyncMain---%@",  [NSThread currentThread]);    });    dispatch_async(mainQueue,  ^{        NSLog(@"3--asyncMain---%@",  [NSThread  currentThread]);    });    NSLog(@"asyncMain  ----- end");}
   打印:
    
    
   2016-10-19 15:39:56.747 GCD基本使用[9750:1398368] asyncMain -----  begin2016-10-19 15:39:56.748 GCD基本使用[9750:1398368] asyncMain -----  end2016-10-19 15:39:56.748 GCD基本使用[9750:1398368] 1--asyncMain---{number = 1, name = main}2016-10-19  15:39:56.753 GCD基本使用[9750:1398368] 2--asyncMain---{number = 1, name = main}2016-10-19  15:39:56.753 GCD基本使用[9750:1398368] 3--asyncMain---{number = 1, name =  main}
   并行队列 同步函数
   ** * 并发队列 + 同步函数:不会开启新的线程,由于不开启新线程,需要等待执行完,所以任务执行完一个,再执行下一个。 */-  (void)syncConcurrent{    //  1.获得全局的并发队列    dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,  0);         //  2.将任务加入队列    dispatch_sync(queue, ^{        NSLog(@"1--syncConcurrent---%@",  [NSThread  currentThread]);    });    dispatch_sync(queue,  ^{        NSLog(@"2--syncConcurrent---%@",  [NSThread  currentThread]);    });    dispatch_sync(queue,  ^{        NSLog(@"3--syncConcurrent---%@",  [NSThread currentThread]);    });    NSLog(@"syncConcurrent--------end");}
   打印:
    
    
   2016-10-19 15:52:30.536 GCD基本使用[9790:1404534]  syncConcurrent--------begin2016-10-19 15:52:30.536 GCD基本使用[9790:1404534]  1--syncConcurrent---{number = 1,  name = main}2016-10-19 15:52:30.536 GCD基本使用[9790:1404534]  2--syncConcurrent---{number = 1,  name = main}2016-10-19 15:52:30.537 GCD基本使用[9790:1404534]  3--syncConcurrent---{number = 1,  name = main}2016-10-19 15:52:30.537 GCD基本使用[9790:1404534]  syncConcurrent--------end
  
   并行队列 异步函数

/** * 并发队列 + 异步函数:可以同时开启多条线程 */-  (void)asyncConcurrent{    NSLog(@"asyncConcurrent--------begin");    //  1.获得全局的并发队列    dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,  0);         //  2.将任务加入队列    dispatch_async(queue,  ^{        NSLog(@"1--asyncConcurrent---%@",  [NSThread  currentThread]);    });    dispatch_async(queue,  ^{        NSLog(@"2--asyncConcurrent---%@",  [NSThread currentThread]);    });    dispatch_async(queue,  ^{        NSLog(@"3--asyncConcurrent---%@",  [NSThread  currentThread]);    });    NSLog(@"asyncConcurrent--------end");}
   打印:
  2016-10-19 15:55:34.637 GCD基本使用[9820:1406397]  asyncConcurrent--------begin2016-10-19 15:55:34.637 GCD基本使用[9820:1406397]  asyncConcurrent--------end2016-10-19 15:55:34.637 GCD基本使用[9820:1406608] 1--asyncConcurrent---{number = 3, name = (null)}2016-10-19  15:55:34.637 GCD基本使用[9820:1406613] 2--asyncConcurrent---{number = 4, name = (null)}2016-10-19  15:55:34.637 GCD基本使用[9820:1406614] 3--asyncConcurrent---{number = 5, name =  (null)}
   
   3 线程间通信
   dispatch_async(dispatch_get_main_queue(), ^{//});
   -  (void)threadCommunication{    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,  0), ^{        //  图片的网络路径        NSURL *url = [NSURL  URLWithString:@"https://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];        //  加载图片        NSData *data = [NSData  dataWithContentsOfURL:url];        //  生成图片        UIImage *image = [UIImage  imageWithData:data];        //  回到主线程        dispatch_async(dispatch_get_main_queue(),  ^{            self.imageView.image  = image;        });    });}
   4 延时
   // 延时追加-  (void)delay{    NSLog(@"delay-----begin");    //延时1s    dispatch_time_t  time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);    dispatch_after(time,  dispatch_get_main_queue(),  ^{        NSLog(@"after------%@",[NSThread  currentThread]);    });    NSLog(@"delay-----end");}
 
   打印:
   16-10-19 16:35:45.680 GCD基本使用[9932:1427078] delay-----begin2016-10-19  16:35:45.680 GCD基本使用[9932:1427078] delay-----end2016-10-19 16:35:46.752  GCD基本使用[9932:1427078] after------{number  = 1, name = main}
   dispatch_after 并不是延时指定时间后执行处理,而是延时指定时间后追加任务到Dispatch Queue。
   其中dispatch_time(DISPATCH_TIME_NOW,1ull*NSEC_PER_SEC);表示从现在开始1s后时间的值。
   DISPATCH_TIME_NOW 表示当前的时间。
   第二个参数单位为纳秒。
   ?1234#define NSEC_PER_SEC 1000000000ull  //每秒有多少纳秒#define  NSEC_PER_MSEC 1000000ull    //每毫秒有多少纳秒#define USEC_PER_SEC  1000000ull     //每秒有多少微秒#define NSEC_PER_USEC  1000ull       //每微秒有多少纳秒
   延时1s写法:
   ?123dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,  1ull*NSEC_PER_SEC);dispatch_time_t time1 = dispatch_time(DISPATCH_TIME_NOW,  1000ull*NSEC_PER_MSEC);dispatch_time_t time2 = dispatch_time(DISPATCH_TIME_NOW,  1000ull*USEC_PER_SEC);
   5Dispatch Group
   开发中会有这种需求,执行多个任务,只有这几个任务都执行完成后才执行最终任务。这种情况可以使用Dispatch Queue。
    
   -  (void)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, ^{        for (int i=0;  i<5; i++)  {            NSLog(@"任务1-------%d",i);        }    });    dispatch_group_async(group,  queue, ^{        for (int i=0;  i<5; i++)  {            NSLog(@"任务2-------%d",i);        }    });    dispatch_group_notify(group,  queue,  ^{        NSLog(@"end.....");    });}
   打印:
2016-10-19 18:05:56.138 GCD基本使用[10052:1471672]  任务1-------02016-10-19 18:05:56.138 GCD基本使用[10052:1471674]  任务2-------02016-10-19 18:05:56.139 GCD基本使用[10052:1471674]  任务2-------12016-10-19 18:05:56.139 GCD基本使用[10052:1471672]  任务1-------12016-10-19 18:05:56.139 GCD基本使用[10052:1471674]  任务2-------22016-10-19 18:05:56.139 GCD基本使用[10052:1471672]  任务1-------22016-10-19 18:05:56.139 GCD基本使用[10052:1471674]  任务2-------32016-10-19 18:05:56.139 GCD基本使用[10052:1471672]  任务1-------32016-10-19 18:05:56.139 GCD基本使用[10052:1471674] 任务2-------42016-10-19  18:05:56.139 GCD基本使用[10052:1471672] 任务1-------42016-10-19 18:05:56.139  GCD基本使用[10052:1471672] end....
   6 dispatch_barrier_async
   在访问数据库或文件时,写入处理确实不可与其他的写入处理以及其他包含读写的处理并行执行。但是读取处理只是和读取处理并行执行就不会发生问题。
   为了高效的进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在一个读取都没有的情况下,追加到Serial  Dispatch Queue中可。利用Dispatch  Group和dispatch_set_target_queue也可以实现,但是会很复杂。
   GCD提供了简便方法——dispatch_barrier_async函数。
    
   -  (void)barrier{    dispatch_queue_t queue =  dispatch_queue_create("abcd",  DISPATCH_QUEUE_CONCURRENT);         dispatch_async(queue,  ^{        NSLog(@"----1-----%@",  [NSThread  currentThread]);    });    dispatch_async(queue,  ^{        NSLog(@"----2-----%@",  [NSThread  currentThread]);    });    dispatch_barrier_async(queue,  ^{        NSLog(@"----barrier-----%@",  [NSThread  currentThread]);    });    dispatch_async(queue,  ^{        NSLog(@"----3-----%@",  [NSThread  currentThread]);    });    dispatch_async(queue,  ^{        NSLog(@"----4-----%@",  [NSThread currentThread]);    });}
   打印:
   2016-10-19 19:18:30.739 GCD基本使用[10096:1490892]  ----2-----{number = 4, name =  (null)}2016-10-19 19:18:30.739 GCD基本使用[10096:1490890] ----1-----{number = 3, name = (null)}2016-10-19  19:18:30.740 GCD基本使用[10096:1490890] ----barrier-----{number = 3, name = (null)}2016-10-19  19:18:30.740 GCD基本使用[10096:1490890] ----3-----{number = 3, name = (null)}2016-10-19  19:18:30.740 GCD基本使用[10096:1490892] ----4-----{number = 4, name =  (null)}
   在前两个任务执行完后,才会追加处理到该queue中。然后当该处理执行完毕后,开始追加其他处理。
   
   7 dispatch_apply
   ?123456789-  (void)apply{    NSLog(@"apply------begin");    dispatch_queue_t  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,  0);    //该函数按指定的次数 将block追加到Dispatch  Queue中。并等待全部处理执行结束。    dispatch_apply(10, queue, ^(size_t  index) {        NSLog(@"apply------%zu",index);    });    NSLog(@"apply------end");}
   打印:
  16-10-19 19:45:19.186 GCD基本使用[10114:1500525]  apply------begin2016-10-19 19:45:19.187 GCD基本使用[10114:1500525]  apply------12016-10-19 19:45:19.187 GCD基本使用[10114:1500833]  apply------02016-10-19 19:45:19.187 GCD基本使用[10114:1500837]  apply------22016-10-19 19:45:19.187 GCD基本使用[10114:1500838]  apply------32016-10-19 19:45:19.187 GCD基本使用[10114:1500525]  apply------42016-10-19 19:45:19.187 GCD基本使用[10114:1500833]  apply------52016-10-19 19:45:19.187 GCD基本使用[10114:1500837]  apply------62016-10-19 19:45:19.187 GCD基本使用[10114:1500838]  apply------72016-10-19 19:45:19.188 GCD基本使用[10114:1500525] apply------82016-10-19  19:45:19.188 GCD基本使用[10114:1500833] apply------92016-10-19 19:45:19.188  GCD基本使用[10114:1500525] apply------end
   可以使用该函数遍历NSArray对象,
   dispatch_apply([array count],queue,^(size_t index){});
   由于dispatch_apply函数与dispatch_sync相同,会等待处理执行结束,因此推荐在dispatch_async函数中异步执行dispatch_apply函数。
    
   -  (void)apply1{    NSLog(@"apply1------begin");    dispatch_queue_t  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,  0);    dispatch_async(queue,  ^{        dispatch_apply(5, queue,  ^(size_t index)  {            NSLog(@"apply------%zu",index);        });        dispatch_async(dispatch_get_main_queue(),  ^{            NSLog(@"done");        });    });    NSLog(@"apply1------end");}
   打印:
   16-10-19 20:26:16.245 GCD基本使用[10143:1518627]  apply1------begin2016-10-19 20:26:16.246 GCD基本使用[10143:1518627]  apply1------end2016-10-19 20:26:16.246 GCD基本使用[10143:1518924]  apply------02016-10-19 20:26:16.246 GCD基本使用[10143:1518928]  apply------12016-10-19 20:26:16.246 GCD基本使用[10143:1518929]  apply------22016-10-19 20:26:16.246 GCD基本使用[10143:1518930]  apply------32016-10-19 20:26:16.246 GCD基本使用[10143:1518924]  apply------42016-10-19 20:26:16.251 GCD基本使用[10143:1518627] done
   8 dispatch_once
   dispatch_once 函数保证应用程序中只执行一次。
    
  - (void)once{    static dispatch_once_t  onceToken;    dispatch_once(&onceToken,  ^{        NSLog(@"------run");    });}
    
        

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    ICP许可  沪B2-20190160

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程