美文网首页
GCD(Grand Central Dispatch) API复

GCD(Grand Central Dispatch) API复

作者: 己庚辛壬癸 | 来源:发表于2018-11-23 15:33 被阅读6次

    1、dispatch_queue_create

    // 示例: 创建一个并行队列
    dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT);
    

    第一个参数为队列的名字,一般使用倒置域名来设置;第二个参数是创建队列的类型:有DISPATCH_QUEUE_SERIALDISPATCH_QUEUE_CONCURRENT两个参数。

    2、获取系统的queue

    • 获取 main queue:dispatch_get_main_queue()
    • 获取 global queue :
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

    获取全局队列时,第一个参数为队列的优先级;第二个参数为标志位,一般设置为0。优先级可供的选项有4个:

    DISPATCH_QUEUE_PRIORITY_HIGH
    DISPATCH_QUEUE_PRIORITY_DEFAULT
    DISPATCH_QUEUE_PRIORITY_LOW
    DISPATCH_QUEUE_PRIORITY_BACKGROUND
    

    3、dispatch_async

    向队列中异步提交Block,不等待Block执行结束。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^ {
        // ...
    });
    

    4、dispatch_sync

    与 dispatch_async 类似,不过是同步向队列提交任务;需要等待block执行完成。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^ {
        // ...
    });
    

    在使用 dispatc_sync 时,注意不要造成死锁,以下代码均会造成死锁:

    // 死锁 
    dispatch_async(dispatch_get_main_queue(), ^ {
        dispatch_sync(dispatch_get_main_queue(), ^ {
                // ...
        });
    });
    
    

    不仅仅是 main_queue 会造成死锁,serial queue 使用如上的代码都会造成死锁。

    5、dispatch_after

    在指定的时间间隔后,将Block提交到指定队列中;注意不是先提交,然后等待指定时间间隔后执行。

    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 3.0);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(time, queue, ^ {
        // do sth ..
    });
    

    6、dispatch_group

    可以使用该API,实现如下功能,在 TASK A 、B 、C 都异步完成后执行TASK D。

    dispatch_group的相关API有:

    • dispatch_group_t dispatch_group_create(void)
    • void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
    • void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t queue, void * context, dispatch_function_t work)
    • long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout)
    • void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
    • void dispatch_group_notify_f(dispatch_group_t group, dispatch_queue_t queue, void * context, dispatch_function_t work)
    • void dispatch_group_enter(dispatch_group_t group)
    • void dispatch_group_leave(dispatch_group_t group)

    使用示例:

    // example 1:
    - (void)groupUse1 {
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        
        dispatch_group_async(group, queue, ^ {
            // Task A ..
            NSLog(@"Task A");
            [NSThread sleepForTimeInterval:2.0];
        });
        
        dispatch_group_async(group, queue, ^ {
            // Task B ..
            NSLog(@"Task B");
            [NSThread sleepForTimeInterval:1.5];
        });
        
        dispatch_group_async(group, queue, ^ {
            // Task C ..
            NSLog(@"Task C");
            [NSThread sleepForTimeInterval:1.0];
        });
        
        dispatch_group_notify(group, queue, ^ {
            // Task D ..
            NSLog(@"Task D");
        });
    }
    
    
    // example 2
    - (void)groupUse2 {
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        
        dispatch_group_enter(group);
        dispatch_async(queue, ^ {
            // Task A ..
            NSLog(@"Task A");
            [NSThread sleepForTimeInterval:2.0];
            dispatch_group_leave(group);
        });
        
        dispatch_group_enter(group);
        dispatch_async(queue, ^ {
            // Task B ..
            NSLog(@"Task B");
            [NSThread sleepForTimeInterval:1.5];
            dispatch_group_leave(group);
        });
        
        dispatch_group_enter(group);
        dispatch_async(queue, ^ {
            // Task C ..
            NSLog(@"Task C");
            [NSThread sleepForTimeInterval:1.0];
            dispatch_group_leave(group);
        });
        
        dispatch_group_notify(group, queue, ^ {
            // Task D ..
            NSLog(@"Task D");
        });
    }
    
    // example 3
    void taskA(void *context) {
        NSLog(@"%s",__func__);
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"%s finished.",__func__);
    }
    
    void taskB(void *context) {
        NSLog(@"%s",__func__);
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"%s finished.",__func__);
    }
    
    void taskC(void *context) {
        NSLog(@"%s",__func__);
        [NSThread sleepForTimeInterval:0.8];
        NSLog(@"%s finished.",__func__);
    }
    
    - (void)use_dispatch_group_3 {
        dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        
        dispatch_group_async_f(group, queue, (__bridge void *)self, &taskA);
        dispatch_group_async_f(group, queue, (__bridge void *)self, &taskB);
        dispatch_group_async_f(group, queue, (__bridge void *)self, &taskC);
        
        dispatch_group_notify(group, queue, ^{
            NSLog(@"Task D");
        });
    }
    
    

    可以使用dispatch_group_wait设置一个超时时间,等待添加到组中的任务执行,如果超时时间内所有与该组相关的任务都完成了,该函数会返回0,未完成的话则反回非0。

    - (void)use_dispatch_group_1 {
        dispatch_group_t group = dispatch_group_create();
        
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"Group 1 : Doing task 1.");
            [NSThread sleepForTimeInterval:1];
            NSLog(@"Group 1 : Task 1 finished.");
        });
        
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"Group 1 : Doing task 2.");
            [NSThread sleepForTimeInterval:3];
            NSLog(@"Group 1 : Task 2 finished.");
        });
        
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"Group 1 : Doing task 3.");
            [NSThread sleepForTimeInterval:2];
            NSLog(@"Group 1 : Task 3 finished.");
        });
        
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"Group 1 : All tasks have done.");
        });
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            long ret = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC));
            if (ret != 0) {
                NSLog(@"Group 1 : 超时 我等不及了~");
            }
            else {
                NSLog(@"Group 1 : 终于等到你");
            }
        });
     }
    

    7、dispatch_barrier_async & dispatch_barrier_sync

    当使用void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block)时,会等待已经加入到了queue中的Block会执行完成,然后再执行dispatch_barrier_async、dispatch_barrier_sync加入的任务(设为 Task barrier),当Task barrier执行完成后才继续执行其他加入到queue中的任务。

    可以用于如下的情况,假设有多个线程会对文件进行读写,读操作可以多个线程一起执行,但是写操作不能够与其他任意操作(读或写)一起执行。

    • 只能用于 CONCURRENT QUEUE
    • 不能用于获取的 Global Queue
    // 示例
    - (void)use_dispatch_barrier_async {
        dispatch_queue_t queue = dispatch_queue_create("com.mytest.gcd", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^ {
            NSLog(@"Reading A ...");
            [NSThread sleepForTimeInterval:2.0];
            NSLog(@"Reading A finised");
        });
        
        dispatch_async(queue, ^ {
            NSLog(@"Reading B ...");
            [NSThread sleepForTimeInterval:1.0];
            NSLog(@"Reading B finised");
        });
        
        dispatch_barrier_async(queue, ^ {
            NSLog(@"Writing ...");
            [NSThread sleepForTimeInterval:5.0];
            NSLog(@"Writing finised");
        });
        
        dispatch_async(queue, ^ {
            NSLog(@"Reading C ...");
            [NSThread sleepForTimeInterval:3.0];
            NSLog(@"Reading C finised");
        });
        
        dispatch_async(queue, ^ {
            NSLog(@"Reading D ...");
            [NSThread sleepForTimeInterval:0.8];
            NSLog(@"Reading D finised");
        });
    }
    

    8、dispatch_semaphore

    该用于控制并发量,当设置并发量为1时,可以当做互斥锁来用。

    dispatch_semaphore_t sema = dispatch_semaphore_create(1);
    NSMutableArray *mArray = [NSMutableArray array];
    for(int i = 0; i < 10000; i ++) {
        dispatch_async(dispatch_get_global_queue(0,0), ^ {
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            [mArray addObject:[[NSObject alloc] init]];
            dispatch_semaphore_signal(sema);
        });
    }
    

    9、dispatch_apply

    函数原型为:void dispatch_apply(size_t iterations, dispatch_queue_t queue, void(^block)(size_t))

    该函数一般用于多次的重复操作;可以用于 serial 和 concurrent 队列。当queue制定为并发队列时,一定要保证多线程操作时是安全的。

    dispatch_apply会等待所有任务都执行完成。

    // 示例
    NSArray *nums = @[@1,@2,@3,@4,@5];
    dispatch_apply(nums.count, dispatch_get_global_queue(0, 0), ^ (size_t index) {
        NSLog(@"%@",nums[index]);
    });
    NSLog(@"Apply Finished.");
    

    10、dispatch_once

    用于只执行一次的任务,是线程安全的;常常用于单例的创建。

    函数原型:void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

    dispatch_once定义:typedef long dispatch_once_t;

    // 使用示例:
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^ {
        // do sth.
    });
    
    

    11、dispatch_set_target_queue

    函数原型:void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);

    设置dispatch_object_t的目标队列;其目标队列负责该object的一系列进程。当设置某些object的目标队列后将改变其相关的一些属性;具体如下:

    • dispatch_queue_t
      • 可以修改其优先级,需要修改优先级时,通过dispatch_get_global_queue来获取正确优先级的 target queue 。
      • 对于 SERIAL QUEUE ,如果将其 target queue 设置为另一个 SERIAL QUEUE ,那么提交到它和它 target queue 中的(或者其他target queue与其target queue 相同的串行队列)block将不会并发执行。

    注意:使用时不要造成循环设置。

    • dispatch_source

      • dispatch_source的target queue 表明了其事件回调和取消回调的Block在哪里提交
    • dispatch I/O

      • dispatch I/O的target queue 指明了I/O操作在哪里执行

    12、dispatch_suspend & dispatch_resume

    用于挂起和重新执行。

    13、dispatch_I/O

    用于在读取较大文件时,将文件分割成小块并行读取。

    14、dispatch_source

    dispatch_source时BSD内核惯有的kqueue的包装,当内核发生各种事件时,它是一个提供给应用层面处理逻辑的接口。

    其能够处理的事件如下:

    类型 描述
    DISPATCH_SOURCE_TYPE_DATA_ADD 变量增加
    DISPATCH_SOURCE_TYPE_DATA_OR 变量OR
    DISPATCH_SOURCE_TYPE_DATA_REPLACE 变量替换
    DISPATCH_SOURCE_TYPE_MACH_SEND MACH 端口发送
    DISPATCH_SOURCE_TYPE_MACH_RECV MACH 端口接受
    DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
    DISPATCH_SOURCE_TYPE_PROC 检测到与进程相关的事件
    DISPATCH_SOURCE_TYPE_READ 可读取文件映像
    DISPATCH_SOURCE_TYPE_SIGNAL 接收信号
    DISPATCH_SOURCE_TYPE_TIMER 定时器
    DISPATCH_SOURCE_TYPE_VNODE 文件系统有变更
    DISPATCH_SOURCE_TYPE_WRITE 可写入文件映像

    下面是已timer为例:

    //  ARC下需要外部保留timer强引用
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"___🙃");
        dispatch_source_cancel(timer);
    });
    dispatch_resume(timer);
    

    相关文章

      网友评论

          本文标题:GCD(Grand Central Dispatch) API复

          本文链接:https://www.haomeiwen.com/subject/mhvjqqtx.html