Connecting the sync world
with the async world
.
@Gero posted an example in this thread, which does away with the need to use semaphores when connecting the sync world
with the async world
.
I have adapted the following example from it to demonstrate its usefulness.
@main
enum sync_async {
static func main () throws {
let sa = SyncAsyncAdaptor ()
sa.enqueue (f)
sa.enqueue (g)
sa.enqueue (h)
#if false
Thread.sleep (until: .now + 19)
#endif
dispatchMain()
}
}
func f () async {
print (#function, "begin...")
try! await Task.sleep (until: .now + .seconds(7))
DispatchQueue.main.async {
print (#function, 1)
}
print (#function, "end.")
}
func g () async {
print (#function, "begin...")
try! await Task.sleep (until: .now + .seconds(10))
DispatchQueue.main.async {
print (#function, 2)
}
print (#function, "end.")
}
func h () async {
DispatchQueue.main.async {
// cause the program to exit
print (#function, "exit...")
exit (0)
}
}
final class SyncAsyncAdaptor {
private let continuation: AsyncStream<() async -> Void>.Continuation
init() {
let (stream, cont) = AsyncStream<() async -> Void>.makeStream()
continuation = cont
Task.detached {
for await workItem in stream {
await workItem ()
}
}
}
deinit {
continuation.finish()
}
func enqueue (_ workItem: @escaping () async -> Void) {
continuation.yield (workItem)
}
}
Produces the output:
f() begin...
f() end.
g() begin...
f() 1
g() end.
g() 2
h() exit...
Program ended with exit code: 0