如何同步启动两个循环任务 (swift)
How to sync start of two cyclic tasks (swift)
我有两个必须定期 运行 的循环。
其中一个循环 (A) 的持续时间是恒定的,而且调度准确度很高,没问题。
另一个循环 (B) 可以有可变的持续时间。比 A 的持续时间短得多或长得多。
但无论 B 的持续时间如何,我都想在下一个 A 周期开始时开始下一个 B 周期。
如果 B 比 A 短得多,那么它必须等待下一个 A' 开始。
如果 B 比 A 长得多,那么,当它完成时,无论发生了多少个 A 循环,它都将等待并在下一个 A 的开始处开始。
我首先想到了使用信号量。 A 会在信号量开始时发出信号,而 B 会在信号量开始时等待它。
如果 B 比 A 短,此方法有效。
但是如果 B 更长,信号量会增加(可能超过 1),我不会让 B 等待,它会在结束时立即重新启动并且开始同步丢失。
任何解决方案(最好使用 GCD,但任何解决方案都可以)?
既然你有使用 GCD 和信号量作为解决方案的想法,我觉得这样的事情也可以通过 OperationQueues
来实现
我喜欢将 OperationQueues
用于您的用例,因为您可以添加依赖项,例如在 B 较长且必须等待当前 A 完成的情况下。
这是我的一个小实验运行,请看看这是否适合您的用例:
带注释的逻辑
// A duration is fixed at 5
let aDuration: UInt32 = 5
// Control B's duration between 1 and 15
let maxBDuration: UInt32 = 15
// Initialize an Operation queue
let operationQueue = OperationQueue()
// Operations A and B which will be initialized
// before being added to a queue
var operationA: BlockOperation!
var operationB: BlockOperation!
// Counters to identify which loop A and B currently
// are in, just for our identification
var aLoopCount = 0
var bLoopCount = 0
// When to stop the experiment
let experimentCount = 10
// Launch the A loop
runALoop()
// Launch the B loop simultaneously specifying
// it is first launch, you will see why soon
runBLoop(isFirstLaunch: true)
// B is identical to A with a few small differences
private func runBLoop(isFirstLaunch: Bool = false)
{
operationB = BlockOperation
{
self.bLoopCount += 1
// The duration of b varies as you mentioned
let duration = UInt32.random(in: 1...self.maxBDuration)
print("Operation B\(self.bLoopCount) started, Duration: \(duration)s")
sleep(duration)
print("Operation B\(self.bLoopCount) done")
if self.bLoopCount != self.experimentCount
{
self.runBLoop()
}
}
// Check if we are not in the first launch
if !isFirstLaunch
{
// Add a dependency of the newly initialize B loop
// To the currently running A so it starts only when
// the current A finishes
operationB.addDependency(operationA)
}
operationQueue.addOperation(operationB)
}
输出
Operation A1 started, Duration: 5s
Operation B1 started, Duration: 14s
Operation A1 done
Operation A2 started, Duration: 5s
Operation A2 done
Operation A3 started, Duration: 5s
Operation B1 done
Operation A3 done
Operation A4 started, Duration: 5s
Operation B2 started, Duration: 13s
Operation A4 done
Operation A5 started, Duration: 5s
Operation A5 done
Operation A6 started, Duration: 5s
Operation B2 done
Operation A6 done
Operation A7 started, Duration: 5s
Operation B3 started, Duration: 8s
Operation A7 done
Operation A8 started, Duration: 5s
Operation B3 done
Operation A8 done
Operation B4 started, Duration: 4s
Operation A9 started, Duration: 5s
Operation B4 done
Operation A9 done
Operation B5 started, Duration: 3s
Operation A10 started, Duration: 5s
Operation B5 done
Operation A10 done
Operation B6 started, Duration: 7s
Operation B6 done
Operation B7 started, Duration: 5s
Operation B7 done
Operation B8 started, Duration: 13s
Operation B8 done
Operation B9 started, Duration: 3s
Operation B9 done
Operation B10 started, Duration: 8s
Operation B10 done
结论
要分析的最有趣的数据是 操作 A10 完成,因为此后 A 不再运行
此输出序列显示了 B 较长时的情况:
Operation A1 started, Duration: 5s
Operation B1 started, Duration: 14s
Operation A1 done
Operation A2 started, Duration: 5s
Operation A2 done
Operation A3 started, Duration: 5s
Operation B1 done
Operation A3 done
Operation A4 started, Duration: 5s
Operation B2 started, Duration: 13s
如您所见,B1
在 A1
开始时开始,并在 A3
完成之前结束,但它会等到 A3
后再以 A4
开始
- 稍后在序列中,它还向您展示了当 B 较短时会发生什么:
Operation B4 started, Duration: 4s
Operation A9 started, Duration: 5s
Operation B4 done
Operation A9 done
Operation B5 started, Duration: 3s
Operation A10 started, Duration: 5s
Operation B5 done
Operation A10 done
Operation B6 started, Duration: 7s
在这种情况下,B4和B5都在当前A操作完成之前结束,但他们等待
- 我觉得这对你有用,因为 B 比 A 短还是长都没有关系,因为 下一个 B 将始终依赖于 当前 A 在开始之前完成执行。
我有两个必须定期 运行 的循环。
其中一个循环 (A) 的持续时间是恒定的,而且调度准确度很高,没问题。
另一个循环 (B) 可以有可变的持续时间。比 A 的持续时间短得多或长得多。 但无论 B 的持续时间如何,我都想在下一个 A 周期开始时开始下一个 B 周期。 如果 B 比 A 短得多,那么它必须等待下一个 A' 开始。 如果 B 比 A 长得多,那么,当它完成时,无论发生了多少个 A 循环,它都将等待并在下一个 A 的开始处开始。
我首先想到了使用信号量。 A 会在信号量开始时发出信号,而 B 会在信号量开始时等待它。 如果 B 比 A 短,此方法有效。
但是如果 B 更长,信号量会增加(可能超过 1),我不会让 B 等待,它会在结束时立即重新启动并且开始同步丢失。
任何解决方案(最好使用 GCD,但任何解决方案都可以)?
既然你有使用 GCD 和信号量作为解决方案的想法,我觉得这样的事情也可以通过 OperationQueues
我喜欢将 OperationQueues
用于您的用例,因为您可以添加依赖项,例如在 B 较长且必须等待当前 A 完成的情况下。
这是我的一个小实验运行,请看看这是否适合您的用例:
带注释的逻辑
// A duration is fixed at 5
let aDuration: UInt32 = 5
// Control B's duration between 1 and 15
let maxBDuration: UInt32 = 15
// Initialize an Operation queue
let operationQueue = OperationQueue()
// Operations A and B which will be initialized
// before being added to a queue
var operationA: BlockOperation!
var operationB: BlockOperation!
// Counters to identify which loop A and B currently
// are in, just for our identification
var aLoopCount = 0
var bLoopCount = 0
// When to stop the experiment
let experimentCount = 10
// Launch the A loop
runALoop()
// Launch the B loop simultaneously specifying
// it is first launch, you will see why soon
runBLoop(isFirstLaunch: true)
// B is identical to A with a few small differences
private func runBLoop(isFirstLaunch: Bool = false)
{
operationB = BlockOperation
{
self.bLoopCount += 1
// The duration of b varies as you mentioned
let duration = UInt32.random(in: 1...self.maxBDuration)
print("Operation B\(self.bLoopCount) started, Duration: \(duration)s")
sleep(duration)
print("Operation B\(self.bLoopCount) done")
if self.bLoopCount != self.experimentCount
{
self.runBLoop()
}
}
// Check if we are not in the first launch
if !isFirstLaunch
{
// Add a dependency of the newly initialize B loop
// To the currently running A so it starts only when
// the current A finishes
operationB.addDependency(operationA)
}
operationQueue.addOperation(operationB)
}
输出
Operation A1 started, Duration: 5s
Operation B1 started, Duration: 14s
Operation A1 done
Operation A2 started, Duration: 5s
Operation A2 done
Operation A3 started, Duration: 5s
Operation B1 done
Operation A3 done
Operation A4 started, Duration: 5s
Operation B2 started, Duration: 13s
Operation A4 done
Operation A5 started, Duration: 5s
Operation A5 done
Operation A6 started, Duration: 5s
Operation B2 done
Operation A6 done
Operation A7 started, Duration: 5s
Operation B3 started, Duration: 8s
Operation A7 done
Operation A8 started, Duration: 5s
Operation B3 done
Operation A8 done
Operation B4 started, Duration: 4s
Operation A9 started, Duration: 5s
Operation B4 done
Operation A9 done
Operation B5 started, Duration: 3s
Operation A10 started, Duration: 5s
Operation B5 done
Operation A10 done
Operation B6 started, Duration: 7s
Operation B6 done
Operation B7 started, Duration: 5s
Operation B7 done
Operation B8 started, Duration: 13s
Operation B8 done
Operation B9 started, Duration: 3s
Operation B9 done
Operation B10 started, Duration: 8s
Operation B10 done
结论
要分析的最有趣的数据是 操作 A10 完成,因为此后 A 不再运行
此输出序列显示了 B 较长时的情况:
Operation A1 started, Duration: 5s
Operation B1 started, Duration: 14s
Operation A1 done
Operation A2 started, Duration: 5s
Operation A2 done
Operation A3 started, Duration: 5s
Operation B1 done
Operation A3 done
Operation A4 started, Duration: 5s
Operation B2 started, Duration: 13s
如您所见,B1
在 A1
开始时开始,并在 A3
完成之前结束,但它会等到 A3
后再以 A4
开始
- 稍后在序列中,它还向您展示了当 B 较短时会发生什么:
Operation B4 started, Duration: 4s
Operation A9 started, Duration: 5s
Operation B4 done
Operation A9 done
Operation B5 started, Duration: 3s
Operation A10 started, Duration: 5s
Operation B5 done
Operation A10 done
Operation B6 started, Duration: 7s
在这种情况下,B4和B5都在当前A操作完成之前结束,但他们等待
- 我觉得这对你有用,因为 B 比 A 短还是长都没有关系,因为 下一个 B 将始终依赖于 当前 A 在开始之前完成执行。