【问题标题】:when should we use semaphore vs dispatch group vs operation queue?我们什么时候应该使用信号量、调度组和操作队列?
【发布时间】:2019-11-24 13:13:11
【问题描述】:
我们什么时候应该使用信号量、调度组和操作队列?
我的理解是:
使用信号量:当多个线程想要访问共享资源时。
使用调度组:当你需要时,你应该在所有线程(添加到调度组)完成它们的执行后得到通知。
使用操作队列:当您希望操作 C 在 A 和 B 完成执行后开始时。所以 A 和 B 对 C 有依赖关系。
我的理解是否正确?
【问题讨论】:
标签:
ios
swift
multithreading
【解决方案1】:
我了解到您正在关注这三种技术管理工作单元之间依赖关系的能力。归根结底,信号量是一种低级工具,调度组代表更高层次的抽象,而操作队列则更高级。
一些观察:
-
作为一般规则,信号量是一种低级工具,应该谨慎使用,因为它们很容易被误用(例如,容易意外导致死锁,容易阻塞主线程,即使使用得当也会不必要地阻塞线程这是低效的,等等)。几乎总是有更好、更高级别的工具。
例如,在进行同步时,锁和 GCD 队列通常不仅提供更高级别的接口,而且效率也更高。
-
调度组是一个更高级别的工具,是在一系列GCD 调度的代码块完成时通知您的好方法。因此,如果您已经在使用 GCD,调度组是一个合乎逻辑的解决方案。
注意,我建议避免使用 wait 函数(无论是信号量还是调度组再现)。请改用调度组notify 方法。使用notify,您可以减轻死锁风险,避免不必要地占用线程,避免阻塞主线程等风险。调度组的wait 函数仅重新引入了一些相同的潜在信号量问题。但是使用notify 时很难(呃)出错。
-
操作队列是一个更高级别的工具。是的,您可以按照您的概述管理依赖项,但您也可以执行更通用的“按顺序运行一系列异步操作”或“运行一系列异步操作,但一次不超过 x 个操作” .这是管理一系列异步任务的好方法。
但操作不仅仅是管理一系列异步工作单元的一种方式。另一个好处是它提供了一个已建立的框架来将一个工作单元包装在一个离散的对象中。这可以帮助我们在代码中实现更好的职责分离。因此,您可以为网络操作设置队列、为图像处理操作设置队列等,并避免出现这种情况,例如,我们将所有这些代码都埋在视图控制器中(lol)。
所以,作为一个严重的过度简化,我建议:
- 完全避免使用信号量;
- 如果您想在一堆已调度的代码块完成时收到通知,请使用带有
notify 模式的调度组;和
- 如果您想将复杂的异步代码抽象为不同的对象,或者有更复杂的异步任务依赖/并发场景,请考虑操作队列。
综上所述,如今,Swift concurrency 系统(又名 async-await)消除了上述大多数模式,允许编写优雅、可读的代码来捕获异步进程。