我正在使用swift 3,来制作延迟事件,这是代码
public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void)
{
let dispatchTime = DispatchTime.now() + seconds
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}
public enum DispatchLevel
{
case main, userInteractive, userInitiated, utility, background
var dispatchQueue: DispatchQueue
{
switch self
{
case .main: return DispatchQueue.main
case .userInteractive: return DispatchQueue.global(qos: .userInteractive)
case .userInitiated: return DispatchQueue.global(qos: .userInitiated)
case .utility: return DispatchQueue.global(qos: .utility)
case .background: return DispatchQueue.global(qos: .background)
}
}
}
override func viewDidAppear(_ animated: Bool)
{
}
override func viewDidLoad()
{
super.viewDidLoad()
for i in 0..<20
{
delay(bySeconds: 1.0+Double(i)*0.5, dispatchLevel: .background)
{
print("__ \(i)")
// delayed code that will run on background thread
}
}
}实际输出,请注意模式在10之后的变化
__ 0
__ 1
__ 2
__ 3
__ 4
__ 5
__ 6
__ 7
__ 8
__ 9
__ 10
__ 12
__ 11
__ 14
__ 13
__ 16
__ 15
__ 17
__ 18
__ 19预期输出
__ 0
__ 1
__ 2
__ 3
__ 4
__ 5
__ 6
__ 7
__ 8
__ 9
__ 10
__ 11
__ 12
__ 13
__ 14
__ 15
__ 16
__ 17
__ 18
__ 19延时延时有问题吗?
发布于 2016-12-17 16:29:56
关键的响应是您正在使用异步函数和并发队列(后台)。
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)上面的代码将立即返回,它只是将任务设置为在未来的时间内执行,因此您的delay函数也将立即返回。因此,这不会阻止循环转到next (与sycn函数一致)。
另一方面,后台队列是一个concurrent队列,这意味着任务不会以添加到队列的相同顺序完成执行,这就解释了你得到的结果。
相反,如果您使用main-queue,因为它是一个串行队列,那么会有一个保证,它会按照添加的顺序逐个执行和完成。但是您将阻止应用程序的UI/响应性
发布于 2016-12-19 09:09:04
您假设当任务首先在并发队列上被调度时,它将首先被执行。并发队列将其任务分布在多个线程上,即使它们按顺序添加到每个线程,每个任务都会有一个随机延迟,这可能会导致它们乱序执行。
为了说明这一点,让我们将您的代码剥离到最低限度,并测量任务的调度时间和实际执行时间:
let queue = DispatchQueue.global(qos: .userInteractive)
for i in 0..<20 {
let scheduledTime = DispatchTime.now() + Double(i) * 0.5
queue.asyncAfter(deadline: scheduledTime) {
let threadID = pthread_mach_thread_np(pthread_self()) // The thread that the task is executed on
let executionTime = DispatchTime.now()
let delay = executionTime.uptimeNanoseconds - scheduledTime.uptimeNanoseconds
print(i, scheduledTime.uptimeNanoseconds, executionTime.uptimeNanoseconds, delay, threadID, separator: "\t")
}
}
// Wait for all the tasks to complete. This is not how you should wait
// but this is just sample code to illustrate a point.
sleep(15)结果,以纳秒为单位(添加了一些格式):
i scheduledTime executionTime delay threadID
0 142,803,882,452,582 142,803,883,273,138 820,556 3331
1 142,804,383,177,169 142,804,478,766,410 95,589,241 3331
2 142,804,883,221,388 142,804,958,658,498 75,437,110 3331
3 142,805,383,223,641 142,805,428,926,049 45,702,408 3331
4 142,805,883,224,792 142,806,066,279,866 183,055,074 3331
5 142,806,383,225,771 142,806,614,277,038 231,051,267 3331
6 142,806,883,229,494 142,807,145,347,839 262,118,345 3331
7 142,807,383,230,527 142,807,696,729,955 313,499,428 3331
8 142,807,883,231,420 142,808,249,459,465 366,228,045 3331
9 142,808,383,232,293 142,808,779,492,453 396,260,160 3331
10 142,808,883,233,183 142,809,374,609,495 491,376,312 3331
12 142,809,883,237,042 142,809,918,923,562 35,686,520 4355
11 142,809,383,234,072 142,809,918,923,592 535,689,520 3331
13 142,810,383,238,029 142,811,014,010,484 630,772,455 3331
14 142,810,883,238,910 142,811,014,040,582 130,801,672 4355
15 142,811,383,239,808 142,812,119,998,576 736,758,768 4355
16 142,811,883,240,686 142,812,120,019,559 236,778,873 3331
18 142,812,883,242,410 142,813,228,621,306 345,378,896 4355
17 142,812,383,241,550 142,813,228,646,734 845,405,184 3331
19 142,813,383,245,491 142,814,307,199,255 923,953,764 3331这20个任务分布在2个线程(3331和4355)上。在每个线程中,任务是按顺序执行的,但是这些线程可能会被发送到不同的CPU核心,从而导致无序执行。每个任务也会随机延迟高达900ms。这就是使用队列的权衡:您无法控制延迟,因为谁知道这些全局队列上还运行着什么。这里有3个选项:
https://stackoverflow.com/questions/41195959
复制相似问题