`DispatchQueue.global().async` 是不是会创建新的全局队列?
Posted
技术标签:
【中文标题】`DispatchQueue.global().async` 是不是会创建新的全局队列?【英文标题】:Does `DispatchQueue.global().async` make new global queue?`DispatchQueue.global().async` 是否会创建新的全局队列? 【发布时间】:2021-12-17 22:50:59 【问题描述】:DispatchQueue.global().async
print("A")
DispatchQueue.global().async
print("B")
DispatchQueue.global().async
print("C")
DispatchQueue.global().async
print("D")
let a = DispatchQueue.global()
a.async
print("A")
a.async
print("B")
a.async
print("C")
a.async
print("D")
如果全局队列没有存储在变量中,那么A、B、C、D的顺序每次都不一样。 当全局队列存储在变量中时,总是按顺序调用 A、B、C 和 D(*在游乐场中)。 我想知道为什么上面和下面的代码执行结果不同。 是否有多个全局队列?
【问题讨论】:
永远不要在操场上测试任何涉及线程或内存管理的东西。 【参考方案1】:其他答案已经讨论了块的执行顺序,但我想直接解决您的问题:“DispatchQueue.global().async
是否创建了一个新的全局队列?”
没有。
我们可以通过打印队列的ObjectIdentifier
来凭经验检查:
import Dispatch
let q = DispatchQueue.global()
print(ObjectIdentifier(DispatchQueue.global()))
print(ObjectIdentifier(q))
它两次打印相同的ObjectIdentifier
,因此对DispatchQueue.global()
的两次调用都返回相同的对象。
我们也可以通过查看源代码来回答这个问题。 DispatchQueue.global()
是 C 函数 dispatch_get_global_queue
的 Swift 包装器。来源是here:
dispatch_queue_global_t
dispatch_get_global_queue(intptr_t priority, uintptr_t flags)
dispatch_assert(countof(_dispatch_root_queues) ==
DISPATCH_ROOT_QUEUE_COUNT);
if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT)
return DISPATCH_BAD_INPUT;
dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
#if !HAVE_PTHREAD_WORKQUEUE_QOS
if (qos == QOS_CLASS_MAINTENANCE)
qos = DISPATCH_QOS_BACKGROUND;
else if (qos == QOS_CLASS_USER_INTERACTIVE)
qos = DISPATCH_QOS_USER_INITIATED;
#endif
if (qos == DISPATCH_QOS_UNSPECIFIED)
return DISPATCH_BAD_INPUT;
return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
它调用_dispatch_get_root_queue
。来源是here:
DISPATCH_ALWAYS_INLINE DISPATCH_CONST
static inline dispatch_queue_global_t
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX))
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
这只是一个数组查找,所以它每次都返回相同的值,除非 _dispatch_root_queues
的内容发生变化——它不会。
【讨论】:
【参考方案2】:它们以正确的顺序打印可能只是一个巧合。 DispatchQueue.global()
的文档说。
提交到返回队列的任务是相对于彼此同时调度的。 https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global#
因为它说它们是同时安排的(而不是串行),所以不应该期望它们总是以相同的顺序打印。
异步任务也没有真正做任何事情。我怀疑它们之间没有足够的可变性导致打印不同的订单。
DispatchQueue.global()
看起来总是根据我在操场上看到的内存地址返回相同的实例。它可能在幕后做了一些额外的事情,可能会在每个异步任务的执行时间上引入一些可变性。
在您的代码中交换两个测试的顺序也为我产生了不同的输出,确认不应该依赖该顺序。
A2
C2
D2
B2
A1
B1
C1
D1
let a = DispatchQueue.global()
a.async
print("A2")
a.async
print("B2")
a.async
print("C2")
a.async
print("D2")
DispatchQueue.global().async
print("A1")
DispatchQueue.global().async
print("B1")
DispatchQueue.global().async
print("C1")
DispatchQueue.global().async
print("D1")
【讨论】:
在 Playground 中执行时,它们按顺序出现,但在 CLT 中执行时,它们是无序的。你能解释一下两者之间的区别吗?【参考方案3】:我运行了你的代码并得到:
B
B
A
D
A
C
C
D
所以所有 8 个打印语句都相互交错,不是完全随机的,但也没有特定的模式。早期的 print 语句往往比后面的更早执行,但基本上它是不可预测的——它是异步的。
【讨论】:
以上是关于`DispatchQueue.global().async` 是不是会创建新的全局队列?的主要内容,如果未能解决你的问题,请参考以下文章
Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`
Swift:使用 DispatchQueue.global (qos: .userInitiated) .asyncAfter 重复返回的结果
Swift:使用DispatchQueue.global(qos:.userInitiated).asyncAfter]重复返回的结果