zoukankan      html  css  js  c++  java
  • GCD(1)

     任务和队列

      执行任务的方式:

    1.用同步的方式执行任务:

     dispatch_sync(dispatch_queue_t queue, ^(void)block);

    queue:队列

    block:任务

    2.用异步方式执行任务:

     dispatch_async(dispatch_queue_t queue, ^(void)block);

    同步和异步的区别:

      同步:只能在当前线程中执行任务,不具备开启新线程的能力

      异步:可以在新的线程中执行任务,具备开启新线程的能力;

    队列的类型:

    并发队列:

      可以让多个任务并发(同时)执行(开启多个线程同时执行任务)

      并发功能只有在异步函数(dispatch_async)下才有效

      全局队列+同步任务/并发队列+同步任务:没有开启新线程,任务是逐个完成的

      全局队列+异步任务/并发队列+异步任务:开启了新线程,任务是并发完成的

      并发队列:

      dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create(“com.example.gcd.MyConcurrentDispatchQueue”,DISPATCH_QUEUE_CONCURRENT);

      全局队列: 

      dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    串行队列:

      dispatch_queue_t  mySerialDispatchQueue = dispatch_queue_create(“com.example.gcd.MySerialDispatchQueue”,NULL);

      主队列:dispatch_get_main_queue();

      让任务一个接着一个的执行(也就是说必须等一个任务执行完毕后才可执行下一个任务)

      串行队列+同步任务:没有开启新的线程,任务逐个完成

      串行多列+异步任务:开启新的线程,任务逐个完成

      主队列+同步任务:死锁;

      主队了+异步任务:没有开启新的线程,任务逐个完成

    并发和串行主要影响任务的执行方式,并发--多个任务并发执行,串行--一个任务完成后,再执行下一个任务

    同步和异步主要影响能不能开启新的线程:同步--在当前线程中执行任务,不具备开启线程的能力;异步:可以在新的线程中执行任务,具备开启新线程的能力

    开发者定义想要执行的任务并追加到适当地Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。

    dispatch_async(queue,^{

         /* 长时间处理

               例如 AR用画像识别

               例如 数据库访问

         */

         /*长时间处理结束,主线程使用该处理结果*/

         dispatch_async(dispatch_get_main_queue(),^{

               /*只在主线程可以执行的处理

                    例如 用户界面更新

               */

         });

    });

    在导入GCD之前,Cocoa框架提供了NSObject类的performSelectorInBackgound:withObject:实例方法和performSelectorOnMainThread实例方法等简单地多线程编程技术

    [self performSelectorInBackground:@selector(doWork) withObject:nil];

    [self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];

    多线程编程容易导致的问题:

    1. 数据竞争:多个线程更新相同的资源会导致数据的不一致
    2. 死锁:停止等待事件的线程会导致多个线程相互持续等待
    3. 使用太多线程会消耗大量内存

    GCDAPI

    开发者定义想要执行的任务并追加到适当地Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。

    dispatch_async(queue,^{

         /*想要执行的任务*/

    });

    Dispatch Queue是执行处理的等待队列。Dispatch Queue按照追加的顺序(先进先出FIFO)执行处理。

    Dispatch Queue的种类:

    1. Serial Dispatch Queue等待现在执行中处理结束,同时只能执行1个追加处理。
    2. Concurrent Dispatch Queue 不等待现在执行中处理结束,可以并行执行多个处理,但并行执行的处理数量取决于当前系统的状态。

    iOS和OS X  的核心-- XNU内核决定应当使用的线程数,并指生成所需的线程执行处理。另外,当处理结束,应当执行的处理数减少时,XUN内核会结束不再需要的线程,XUN内核仅使用Concurrent Dispatch Queue便可完美地管理并执行多个处理的线程

    dispatch_queue_create

    第一种方法是通过GCD的API生成Dispatch Queue。

    通过dispatch_queue_create函数可生成Dispatch Queue:

    dispatch_queue_t  mySerialDispatchQueue = dispatch_queue_create(“com.example.gcd.MySerialDispatchQueue”,NULL);

    该函数的第一个参数是指定Serial Dispatch Queue的名称,推荐使用应用程序ID这种逆序全程域名,该名称在Xcode和Instruments的调试器中作为Dispatch Queue名称表示,另外该名称也出现在应用程序崩溃时所生成的CrashLog中。

    第二个参数:生成Serial Dispatch Queue时,第二个参数指定为NULL;生成Concurrent Dispatch Queue时,指定为    DISPATCH_QUEUE_CONCURRENT.

    返回值:dispatch_queue_t类型变量

    注:尽管有ARC这一通过编译器自动管理内存的优秀技术,但生成的Dispatch Queue必须由程序员负责释放。Dispatch_queue_create函数生成的Dispatch Queue在使用结束后通过dispatch_release函数释放。

    用dispatch_queue_create函数可生成任意多个Dispatch Queue,dispatch_queue_create生成的多个Serial Dispatch Queue 可并行执行

    dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create(“com.example.gcd.MyConcurrentDispatchQueue”,DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(myConcurrentDispatchQueue,^{NSLog(@”block on myConcurrentDispatchQueue”);});

    dispatch_retain(myConcurrentDispatchQueue);

    dispatch_release(myConcurrentDispatchQueue);

    Main Dispatch Queue /Global Dispatch Queue

    第二种方法是获取系统标准提供的Dispatch Queue

    Main Dispatch Queue是在主线程中执行的Dispatch Queue,因为主线程只有一个,所以Main Dispatch Queue自然是Serial Dispatch Queue;

    Global Dispatch Queue是所有应用程序都能够使用的Concurrent Dispatch Queue,没有必要通过函数逐个生成Concurrent Dispatch Queue,只要获取Global Dispatch Queue使用即可。

    Global Dispatch Queue有4个优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(Low Priority)和后台优先级(Background Priority)。通过XUN内核管理的用于Global Dispatch Queue的线程,将各自使用的Global Dispatch Queue的执行优先级作为线程的执行优先级使用。在向Global Dispatch Queue追加处理时,应选择与处理内容对应的执行优先级的Global Dispatch Queue

    //Main Dispatch Queue的获取方法

    Dispatch_queue_t  mainDispatchQueue = dispatch_get_main_queue();

    //Global Dispatch Queue(高优先级)的获取方法

    dispatch_queue_t  globalDispatchQueueHight = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);

    //Global Dispatch Queue(默认优先级)的获取方法

    dispatch_queue_t  globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_D    EFAULT,0);

    //Global Dispatch Queue(低优先级)的获取方法

    dispatch_queue_t  globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);

    //Global Dispatch Queue(后台优先级)的获取方法

    dispatch_queue_t  globalDispatchQueueHight = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);

    Main Dispatch Queue 和Global Dispatch Queue执行dispatch_retain函数和dispatch_release函数不会引起任何变化,也不会有任何问题

    //在默认优先级的Global Dispatch Queue中执行Block

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

              

    /*可并行执行的处理*/

               //在Main Dispatch Queue中执行Block

               dispatch_async(dispatch_get_main_queue(),^{

         //只能在主线程中执行的处理

    });

    });

    线程间通信

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            NSURL *url = [NSURL URLWithString:IMAGE_URL];

            NSData *data = [NSData dataWithContentsOfURL:url];

            UIImage *image= [UIImage imageWithData:data];

            //回归到主线程

            dispatch_async(dispatch_get_main_queue(), ^{

                self.imageView.image = image;

            });

            

        });

    dispatch_set_target_queue

    dispatch_queue_create函数生成的Dispatch Queue不管是Serial Dispatch Queue还是Concurrent Dispatch Queue,都使用默认优先级Global Dispatch Queue相同执行优先级的线程,而变更生成的Dispatch Queue的执行优先级要使用dispatch_set_target_queue函数,

    dispatch_queue_t  mySerialDispatchQueue = dispatch_queue_create(“com.example.gcd.MySerialDispatchQueue”,NULL);

    dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGOUND,0);

    dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);

    指定要变更优先级的Dispatch Queue 为dispatch_set_target_queue函数的第一个参数,指定要使用的执行优先级相同优先级的Global Dispatch Queue为第二个参数(目标),第一个参数如果指定系统提供的Main Dispatch Queue 和Global Dispatch Queue则不知道会出现什么状况,因此这些均不可指定

    将Dispatch Queue指定为dispatch_set_target_queue函数的参数,不仅可以变更Dispatch Queue的执行优先级,还可以作成Dispatch Queue的执行阶层;如果在多个Serial Dispatch Queue中用dispatch_set_target_queue函数指定目标位某一Serial Dispatch Queue,那么原先本应并行执行的多个Serial Dispatch Queue,在目标Serial Dispatch Queue上只能同时执行一个处理。

    dispatch_after

    想在指定时间(3秒,可能不仅限于3秒)后执行处理,用dispatc_after来实现

    dispatch_time_t  time = dispatch_time( DISPATCH_TIME_NOW,3ull*NSEC_PER_SEC);

    //150毫秒:150ull*NSEC_PER_MSEC

    dispatch_after(time,dispatch_get_main_queue(),^{

               NSLog(@”waited at least three seconds.”);

         });

    dispatch_after第一个参数是dispatch_time_t类型的值,该值使用dispatch_time函数或dispatch_walltime函数作成

    Dispatch Group

    在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理。

    只使用一个Serial Dispatch Queue时,只要将想要执行的处理全部追加到该Serial Dispatch Queue中并在最后追加结束处理,即可实现,但是在使用Concurrent Dispatch Queue时或同时使用多个Dispatch Queue时,源代码就会变得颇为复杂->使用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(@”blk0”);});

    dispatch_group_async(group,queue,^{NSLog(@”blk1”);});

    dispatch_group_async(group,queue,^{NSLog(@”blk2”);});

    dispatch_group_notify(group,dispatch_get_main_queue(),^{NSLog(@”done”);});

    因为向Global Dispatch Queue 即Concurrent Dispatch Queue 追加处理,多个线程并行执行,所以追加处理的执行顺序不定,执行时会发生变化,但是执行结果的done一定是最后输出的。监视Dispatch Group的执行结束后,将结束的处理追加到Dispatch Queue中

    可以使用dispatch_group_wait函数仅等待全部处理执行结束

    dispatch_time_t  time = dispatch_time( DISPATCH_TIME_NOW,1ull*NSEC_PER_SEC);

    long result = dispatch_group_wait(group,time);

    if(result == 0)

    {

         //属于Dispatch Group的全部处理执行结束

    }else {

         //属于Dispatch Group的某一个处理还在执行中

    }

    当等待时间为  DISPATCH_TIME_FOREVER由dispatch_group_wait函数返回时,由于属于Dispatch Group 的处理必定全部执行结束,因此返回值恒为0;

    dispatch_barrier_async

    在访问数据库或文件时,避免数据竞争

    dispatch_queue_t  queue = dispatch_queue_create(“com.example.gcd,ForBarrier”,DISPATCH_QUUE_CONCURRENT);

    dispatch_async(queue,blk0_for_reading);

    dispatch_async(queue,blk1_for_reading);

    dispatch_async(queue,blk2_for_reading);

    /*写处理,将写入的内容供之后的读取操作*/

    dispatch_barrier_async(queue,blk_for_writing)

    dispatch_async(queue,blk3_for_reading);

    dispatch_async(queue,blk4_for_reading);

    dispatch_async(queue,blk5_for_reading);

  • 相关阅读:
    刷题系列
    元类编程
    Python内置方法与面向对象知识点进阶系列
    json反序列化的时候字符串为单引号的一个坑
    刨根问底,完美解决Django2版本连接MySQL报错的问题
    使用mkdocs撰写技术文档并免费部署上线
    关于Python的源文件编译看这一篇就够了
    SQL查询where语句后面字符串大小写问题
    configparser模块获取settings.ini文件中的配置数据
    Sharepoint 2013列表视图和字段权限扩展插件(免费下载)!
  • 原文地址:https://www.cnblogs.com/PJXWang/p/4916232.html
Copyright © 2011-2022 走看看