zoukankan      html  css  js  c++  java
  • GCD 多线程技术

     Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用

    的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成

    必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可以统一管理,也可以执行任务,

    这样就比以前的线程更有效率。

    GCD API 

    1. Dispatch Queue 队列

    队列有两种类型:

    Serial Dispatch Queue 串行队列,使用一个线程,按照追加的顺序(先进先出FIFO)执行处理。多个串行队列之间是并行处理的。
    Concurrent Dispatch Queue 并行队列,使用多个线程,并发处理

    2.diapatch_queue_create

    创建 Serial Queue:

    dispatch_queue_t mySerailQueue = dispatch_queue_create("com.r.dispatchSerailQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.r.dispatchConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

    第一个参数是指定 Serial dispatch queue 的名称。该名称在Xcode和Instruments的调试器中作为Dispatch Queue名称.

    第二个参数是生成Dispatch Queue的类型,如果是NULL 或者 DISPATCH_QUEUE_SERIAL生成串行队列,

    指定为DISPATCH_QUEUE_CONCURRENT生成并发队列.

    3.Main Dispatch Queue/Global Dispatch Queue

    获取系统标准提供的Dispatch Queue。

    Main Dispatch Queue是在主线程执行的dispatch queue, Main Dispatch Queue是一个Serail Dispatch Queue。追加到Main Dispatch Queue的处理在主线程的RunLoop中执行。一般将用户界面更新等必需要在主线程中执行的处理追加到Main Dispatch Queue中。

    Global Dispatch Queue是所有应用程序都能过使用的Concurrent Dispatch Queue。没有必要通过dispatch_queue_create函数逐个创建Concurrent Dispatch Queue,只要获取Global Dispatch Queue使用即可。Global Dispatch Queue有四个优先级

    名称Dispatch Queue的种类说明
    Main Dispatch Queue Serial Dispatch Queue 主线程执行
    Global Dispatch Queue(High Priority) Concurrent Dispatch queue 执行优先级:高(最高)
    Global Dispatch Queue(Default Priority) Concurrent Dispatch queue 执行优先级:默认
    Global Dispatch Queue(Low Priority) Concurrent Dispatch queue 执行优先级:低
    Global Dispatch Queue(Background Priority) Concurrent Dispatch queue 执行优先级:后台

    获取Dispatch Queue方法:

    dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
    
    dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

    使用Main Dispatch Queue 和 Global Dispatch Queue

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            /**
             *  可并行处理的任务TODO
             */
    
            dispatch_async(dispatch_get_main_queue(), ^{
                /**
                 *  主线程执行
                 */
            });
        });
    
    

    4. dispatch_after

    dispatch_after表示在指定的时间之后追加处理到Dispatch Queue。并不是指定时间后执行处理。

    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
            NSLog(@"等待3秒后执行");
     });

    虽然在有严格时间到要求下使用时会出现问题,但在大致延迟执行处理时,该函数还是有效的。

    5.dispatch_suspend/dispatch_resume

    当追加大量处理到Dispatch Queue时,在追加处理到过程中,有时希望不执行已追加的处理。在这种情况下只要挂起Dispatch Queue即可。

    dispatch_suspend 函数挂起指定的Dispatch Queue

    dispatch_resume 函数恢复指定的Dispatch Queue

    这些函数对已经执行的处理没有影响,挂起后,追加到Dispatch Queue中处理在此之后暂停执行,而恢复使得这些处理继续执行。

    6.Dispatch Group

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

    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<2000; i++) {
                NSLog(@"111111");
            }
        });
        dispatch_group_async(group, queue, ^{
            for (int i=0; i<2000; i++) {
                NSLog(@"2222222");
            }
        });
        dispatch_group_async(group, queue, ^{
            for (int i=0; i<2000; i++) {
                NSLog(@"33333");
            }
        });
        //最后执行4444
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"44444");
        });
        NSLog(@"555555");

    7. dispatch_barrier_async

       dispatch_async(queue, ^{
            //读文件
        });
        dispatch_async(queue, ^{
             //读文件
        });
    
        //使用dispatch_barrier_async避免数据竞争
        dispatch_barrier_async(queue, ^{
            //写文件
        });
        dispatch_async(queue, ^{
            //读文件
        });
        dispatch_async(queue, ^{
            //读文件
        });

    一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,

    等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作。

    调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。当barrier block到并发队列的最前端,

    他不会立即执行。相反,队列会等到所有当前正在执行的blocks结束执行。到这时,barrier才开始自己执行。

    所有在barrier block之后提交的blocks会等到barrier block结束之后才执行

    这里指定的并发队列应该是自己通过dispatch_queue_create函数创建的。

    如果你传的是一个串行队列或者全局并发队列,这个函数等同于dispatch_async函数。

    8.dispatch_apply

    dispatch_apply函数是dispatch_sync函数和Dispatch Group的关联API。

    该函数按指定的次数将指定的Block追加到Dispatch Queue中,并等待全部处理执行结束。

    1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    2     dispatch_apply(10, queue, ^(size_t index) {
    3         NSLog(@"%zu", index);//并行
    4     });
    5     //最后执行
    6     NSLog(@"11");

    9. Dispatch Semaphore

    信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。

     1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     2     
     3     /**
     4      * 生成Dispatch Semaphore
     5      * Dispatch Semaphore 的计数初始值设定为1
     6      * 保证可访问NSMutableArray类对象的线程同时只有一个
     7      */
     8     dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
     9     NSMutableArray *array = [[NSMutableArray alloc] init];
    10     
    11     for (int i=0; i<10000; i++) {
    12         dispatch_async(queue, ^{
    13             /**
    14              *  等待Dispatch Semaphore
    15                 一直等待,直到Dispatch Semaphore 的计数的值达到大于等于1
    16              */
    17             dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    18             
    19             /**
    20              *  由于Dispatch Semaphore 的计数达到大于等于1
    21              所以Dispatch Semaphore 的计数值减去1
    22              dispatch_semaphore_wait函数执行返回
    23              
    24              即执行到此时Dispatch Semaphore的计数值恒为00
    25              
    26              由于可访问NSMutableArray类对象的线程数只有1个
    27              因此可安全的进行更新
    28              */
    29             [array addObject:[NSNumber numberWithInt:i]];
    30             
    31             /**
    32              * 排他控制处理结束
    33              所以通过dispatch_semaphore_signal函数
    34              将DispatchSemaphore的计数值加1
    35              如果有通过dispatch_semaphore_wait函数
    36              等待Dispatch Semaphore的计数值增加的线程
    37              就由最先等待的线程执行。
    38              */
    39             dispatch_semaphore_signal(semaphore);
    40         });
    41     }
  • 相关阅读:
    【276】◀▶ Python 字符串函数说明
    Spring事务配置的五种方式 巨全!不看后悔,一看必懂!
    Android Developers:两个视图渐变
    《Linux命令行与shell脚本编程大全》 第二十七章 学习笔记
    Android的TextView与Html相结合的用法
    嵌入式C语言优化小技巧
    vxworks获取系统时间编程
    【算法与数据结构】在n个数中取第k大的数(基础篇)
    字符集转换 字符类型转换 utf-8 gb2312 url
    java 从零开始,学习笔记之基础入门<Oracle_基础>(三十三)
  • 原文地址:https://www.cnblogs.com/miaocunfa/p/9663592.html
Copyright © 2011-2022 走看看