如何同步启动两个循环任务 (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

结论

  1. 要分析的最有趣的数据是 操作 A10 完成,因为此后 A 不再运行

  2. 此输出序列显示了 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

如您所见,B1A1 开始时开始,并在 A3 完成之前结束,但它会等到 A3 后再以 A4 开始

  1. 稍后在序列中,它还向您展示了当 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操作完成之前结束,但他们等待

  1. 我觉得这对你有用,因为 B 比 A 短还是长都没有关系,因为 下一个 B 将始终依赖于 当前 A 在开始之前完成执行。