Swift异步函数无异步代码仍触发线程切换的疑问
Swift异步函数无异步代码仍触发线程切换的疑问
嘿,我来帮你捋清楚这个困惑~
首先,你观察到的线程切换是完全正常的,咱们从几个关键点拆解:
1. 文章描述的核心是「无挂起则无额外性能开销」,而非「不切换线程」
你看到的文章里说的是如果没有挂起发生,函数执行不会有暂停,效率和同步函数一致,但这句话并没有承诺「不会切换线程」。Swift的并发调度器有自己的调度策略,它会根据当前系统的线程负载、任务优先级等因素,灵活决定把异步任务放到哪个线程执行——哪怕这个异步函数里没有任何await挂起点。
2. 你的测试结果背后的逻辑
先看你输出的日志:
init thread = <_NSMainThread: 0x600001704000>{number = 1, name = main} task start thread = <_NSMainThread: 0x600001704000>{number = 1, name = main} fake expensive work thread = <NSThread: 0x60000176ae00>{number = 6, name = (null)} task end thread = <_NSMainThread: 0x600001704000>{number = 1, name = main}
.task修饰符绑定到View生命周期,默认会在View所在的主线程启动,所以task start在主线程- 调用
fakeExpensiveWork()时,调度器判断把这个任务放到后台线程更合适(哪怕只是打印日志),所以发生了线程切换 - 当你加入
Thread.sleep(forTimeInterval: 10)后,列表依然能流畅滚动,是因为sleep阻塞的是后台线程,主线程完全不受影响——这其实是Swift并发的优势:自动把同步耗时操作移到后台,避免阻塞UI线程
3. Swift版本的变化影响吗?
从Swift 5.5引入并发到5.10,调度器的策略确实有一些优化,但核心逻辑没变:异步函数的执行线程由调度器管理,而非强制和调用者同线程。文章的描述并没有错误,只是它侧重的是「挂起带来的额外等待开销」,而不是「线程切换的必然性」。
总结一下:你并没有误解文章,也不是Swift的行为突变——只是调度器的线程分配策略和你预期的「同步函数必在原线程执行」不一样而已。这种切换是调度器的正常操作,而且不会带来文章里提到的「等待runloop」的性能损耗。
备注:内容来源于stack exchange,提问作者LittleExp
相关产品推荐
相关产品推荐

