GCD使用总结

GCD

Grand Central Dispatch (GCD) is a technology developed by Apple Inc. to optimize application support for systems with multi-core processors and other symmetric multiprocessing systems.

Dispatch Queue 种类

Dispatch Queue 是一个先进先出的队列(FIFO,First-In-First-Out)。按照添加的顺序进行处理。执行处理时存在两种方式:

  • Serial Dispatch Queue,等待现在的执行处理结束
  • Concurrent Dispatch Queue,不等待现有执行处理结束

GCD Thread

创建队列及内存管理

1
2
dispatch_queue_t serialQueue;
serialQueue = dispatch_queue_create("com.example.MySerialQueue", NULL);
1
2
dispatch_queue_t concurrentQueue;
concurrentQueue = dispatch_queue_create("com.example.MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
  • dispatch_queue_create默认生成的 Queue 引用计数为1,使用完成后需要使用dispatch_release进行释放资源。
  • 若使用其他地方生产的 Queue,避免在使用过程中 Queue 被释放了,需要调用dispatch_retain增加引用计数,使用结束后调用dispatch_release释放资源。

获取全局队列

获取主线程队列,主线程为 Serial Queue:

1
dispatch_queue_t aQueue = dispatch_get_main_queue()

获取全局队列,为 Concurrent Queue:

1
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Block的类:

Queue优先级
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台

dispatch_set_target_queue

dispatch_set_target_queue 可指定 Dispatch Queue 执行优先级、阶层:

dispatch_after

指定时间后,追加处理到 Dispatch Queue。
可使用 dispatch_time函数(相对)或dispatch_walltime 函数(绝对)生成的时间。

Dispatch Group

可使用 dispatch_group_wait 主动等待 group 中任务完成,或使用dispatch_group_notify 配置 group 完成后需要执行的 Block 及执行所用的队列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

// Add a task to the group
dispatch_group_async(group, queue, ^{
// Some asynchronous work
});

// Do some other work while the tasks execute.

// When you cannot make any more forward progress,
// wait on the group to block the current thread.
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

//dispatch_group_notify(group, doneQueue, ^{
//Do some thing after
//});

// Release the group when it is no longer needed.
dispatch_release(group);

dispatch_group_wait 也可指定时间,若在指定时间未完成,将会返回非0

dispatch_barrier_async

下图很好的说明了 dispatch_barrier_async 的效果:

sync

与async相对,sync为同步操作,会在调用处阻塞知道执行完成。使用时需要注意不要出现死锁

dispatch_apply

按指定的次数将指定的 Block 追加到指定的 Dispatch Queue,并等待全部处理执行结束。可以用来提高循环的效率:

1
2
3
4
5
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(count, queue, ^(size_t i) {
printf("%u\n",i);
});

dispatch_suspend/dispatch_resume

挂起/恢复队列

Dispatch Semaphore

Dispatch Semaphore 可以更细的控制资源:

1
2
3
4
5
6
7
8
9
10
// Create the semaphore, specifying the initial pool size
dispatch_semaphore_t fd_sema = dispatch_semaphore_create(getdtablesize() / 2);

// Wait for a free file descriptor
dispatch_semaphore_wait(fd_sema, DISPATCH_TIME_FOREVER);
fd = open("/etc/services", O_RDONLY);

// Release the file descriptor when done
close(fd);
dispatch_semaphore_signal(fd_sema);

dispatch_once

只会执行一次,一般单例中使用:

1
2
3
4
5
6
7
8
9
+ (instancetype)sharedManager {
static Manager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [self manager];
});

return _sharedManager;
}

Dispatch I/O

可以提交读写文件的效率,用的不多,具体实现可参考苹果:Processing a File Using GCD

Dispatch Source

Dispatch Source 可处理以下事件:

Dispatch Source 类型 内容
DISPATCH_SOURCE_TYPE_DATA_ADD 变量增加
DISPATCH_SOURCE_TYPE_DATA_OR 变量OR
DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口发送
DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口接收
DISPATCH_SOURCE_TYPE_PROC 进程相关事件
DISPATCH_SOURCE_TYPE_READ 可读取文件映像
DISPATCH_SOURCE_TYPE_SIGNAL 接收信号
DISPATCH_SOURCE_TYPE_TIMER 定时器
DISPATCH_SOURCE_TYPE_VNODE 文件系统有变更
DISPATCH_SOURCE_TYPE_WRITE 可写入文件映像
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE 内存压力

timer的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
dispatch_source_t CreateDispatchTimer(uint64_t interval,
uint64_t leeway,
dispatch_queue_t queue,
dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}

void MyCreateTimer()
{
dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC,
1ull * NSEC_PER_SEC,
dispatch_get_main_queue(),
^{ MyPeriodicTask(); });

// Store it somewhere for later use.
if (aTimer)
{
MyStoreTimer(aTimer);
}
}
Cotin Yang wechat
欢迎订阅我的微信公众号 CotinDev
小小地鼓励一下吧~😘