GCD(Grand Central Dispatch) API复

2018-11-23  本文已影响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

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有:

使用示例:

// 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中的任务。

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

// 示例
- (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的目标队列后将改变其相关的一些属性;具体如下:

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

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);
上一篇下一篇

猜你喜欢

热点阅读