Here's a proof of concept implementation of the hybrid approach
let serialQueue = OperationQueue()
serialQueue.maxConcurrentOperationCount = 1
func foo(_ name: String, timeout: UInt64) async {
await serialQueue.addAsynchronousOperation {
print("\(name) op started")
try await Task.sleep(nanoseconds: timeout)
print("\(name) op finished")
}
}
func test() async {
await foo("first", timeout: 2_000_000_000)
await foo("second", timeout: 1_000_000_000)
}
print("Start")
Task {
await test()
}
RunLoop.main.run(until: .distantFuture)
print("Stop")
print()
extension OperationQueue {
func addAsynchronousOperation<T>(_ block: @escaping () async throws -> T) async {
addAsynchronousOperation { finish in
Task { () -> T in
let result = try await block()
finish()
return result
}
}
}
}
where "AsynchronousOperation" is taken from the link you provided above.
The test gives desired output:
Start
first op started
first op finished
second op started
second op finished