macOS控制台应用中Swift async/await问题:Task未执行
为什么你的Swift控制台Task没执行?怎么解决?
问题原因
你的代码里,readLine()是阻塞式的同步调用,会直接卡住主线程。而Swift的Task依赖系统的并发执行器调度,控制台程序默认不会自动启动RunLoop来处理异步任务——主线程被readLine()占住后,程序完全没机会调度执行Task的闭包,所以循环任务根本没开始。
解决方法
控制台程序需要手动维持并发执行的环境,这里提供两种可行方案:
方案1:后台线程处理输入,主线程启动RunLoop
把输入操作放到后台队列,避免阻塞主线程,同时让主线程运行RunLoop来调度异步任务:
import Foundation func dummyLoop() async { print("inside dummy fcn") for i in 0 ..< 10 { guard !Task.isCancelled else { return } print("Loop \(i)") try? await Task.sleep(for: .seconds(1)) } } let task = Task(priority: .high) { await dummyLoop() } // 后台线程处理用户输入,不阻塞主线程 DispatchQueue.global().async { print("Press any key to stop task...") _ = readLine() task.cancel() print("Press any key to finish app...") _ = readLine() exit(0) // 主动退出程序 } // 启动主线程RunLoop,让异步任务有机会被调度执行 RunLoop.main.run(until: .distantFuture)
方案2:用异步方式处理输入(更贴合Swift并发风格)
用withCheckedContinuation把同步的readLine()包装成异步操作,将整个交互逻辑放到Task中,最后启动RunLoop维持程序运行:
import Foundation func dummyLoop() async { print("inside dummy fcn") for i in 0 ..< 10 { guard !Task.isCancelled else { return } print("Loop \(i)") try? await Task.sleep(for: .seconds(1)) } } Task { let loopTask = Task(priority: .high) { await dummyLoop() } print("Press any key to stop task...") // 把同步readLine转为异步操作 await withCheckedContinuation { continuation in DispatchQueue.global().async { _ = readLine() continuation.resume() } } loopTask.cancel() print("Press any key to finish app...") await withCheckedContinuation { continuation in DispatchQueue.global().async { _ = readLine() continuation.resume() } } print("Ciao") exit(0) } // 启动RunLoop保证异步任务能被调度 RunLoop.main.run(until: .distantFuture)
关键知识点
- iOS/macOS应用的主线程默认会启动RunLoop,自动调度异步任务;但控制台程序的主线程执行完同步代码就会退出,必须手动启动RunLoop或通过其他方式维持程序运行。
Task.sleep()这类异步函数需要依赖执行器调度,主线程被阻塞时,调度器根本没机会执行Task的闭包。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

