ByAI:Task.sleep() 与 Task.yield() 的区别解析

9 阅读2分钟

在Swift并发编程中,Task.sleep()Task.yield()都能暂停任务执行,但二者适用场景和机制有显著差异。以下通过示例和对比说明它们的核心区别。


1. Task.sleep():延迟执行

作用:暂停任务指定时间,期间允许其他任务运行,且不会阻塞底层线程。
特点

  • 可设置固定延迟时间(如秒、毫秒)。
  • 若任务在休眠期间被取消,会抛出CancellationError

典型场景

  • 用户输入防抖:延迟搜索请求,避免频繁触发。
func search(_ query: String) {
    currentSearchTask?.cancel()  // 取消之前的搜索任务
    currentSearchTask = Task {
        try await Task.sleep(for: .milliseconds(500))  // 等待用户停止输入
        guard !Task.isCancelled else { return }
        // 执行搜索逻辑
    }
}

2. Task.yield():协作式让出执行权

作用:立即暂停当前任务,允许其他任务执行。
特点

  • 不保证暂停时间,若当前任务优先级最高,可能立即恢复执行。
  • 不响应取消操作(无错误抛出)。

典型场景

  • 异步测试:确保其他任务优先执行后再验证结果。
func testIsLoading() async {
    await withMainSerialExecutor {
        let model = NumberFactModel {
            await Task.yield()  // 让出执行权,允许测试逻辑先运行
            return "($0) is a good number."
        }
        let task = Task { await model.getFactButtonTapped() }
        await Task.yield()  // 等待模型内部逻辑执行
        XCTAssertEqual(model.isLoading, true)
        await task.value
    }
}

3. 核心差异对比
特性Task.sleep()Task.yield()
暂停时间固定时长(可指定)不确定(可能立即恢复)
响应取消是(抛出错误)
适用场景延迟执行、轮询、限流协作式任务切换、测试辅助
底层线程影响不阻塞不阻塞

总结
  • 优先使用Task.sleep() :需要明确延迟或可取消的暂停操作(如用户输入防抖)。
  • 谨慎使用Task.yield() :仅在需要强制让出执行权时使用(如测试或避免长时间阻塞其他任务)。
  • 关键区别sleep控制精确延迟,yield仅协作式让出执行权,实际效果受优先级影响。

合理选择二者,可优化任务调度效率,避免资源浪费。

原文链接

www.avanderlee.com/concurrency…