为什么我不能在Swift 5.8项目中导入并发?

tkclm6bt  于 2023-05-05  发布在  Swift
关注(0)|答案(1)|浏览(185)

我试着编译这个简单的例子,首先Xcode 14.3(Swift 5.8)告诉我

No such module 'Concurrency'

然后,如果我将该行更改为import _Concurrency,Xcode14.3会告诉我

Cannot find 'withTimeout' in scope

使用'withDeadline()'也是如此。怎么了?

import Foundation
import Concurrency

func fetchImageData() async throws -> Data {
    return try await withTimeout(1)  {
        // Simulate a long-running async operation
        let imageData = try await URLSession.shared.data(from: URL(string: "https://example.com/image.jpg")!)
        return imageData.0
    }
}
8iwquhpp

8iwquhpp1#

Swift并发不需要import任何东西,因为它是为你导入的。
但是没有withTimeout函数。你可以写一个。或许:

extension Task where Failure == Error {
    /// Run asynchronous task, but cancel it if not finished within a certain period of time.
    ///
    /// - Parameters:
    ///   - duration: The duration before the task is canceled.
    ///   - operation: The async closure to run. The code therein should support cancelation.
    /// - Throws: If canceled, will throw `CancellationError`. If the task fails, this will throw the task’s error.
    /// - Returns: This will return the value returned by the `async` closure.

    static func withTimeout(_ duration: Duration, operation: @Sendable @escaping () async throws -> Success) async rethrows -> Success {
        let operationTask = Task.detached {
            try await operation()
        }

        let cancelationTask = Task<Void, Error>.detached {
            try await Task<Never, Never>.sleep(for: duration)
            operationTask.cancel()
        }

        return try await withTaskCancellationHandler {
            defer { cancelationTask.cancel() }
            return try await operationTask.value
        } onCancel: {
            operationTask.cancel()
        }
    }
}

不用说,我用更通用的Duration替换了TimeInterval(即秒),并使其成为Taskstatic方法,但总体思路很简单:基本上,为提供的闭包启动一个任务,为取消另一个任务启动另一个任务,无论哪个先完成都会取消另一个任务。显然,如果withTimeout本身被取消,那么也要取消非结构化并发任务。
但不要迷失在这杂草,因为可能有许多变化的主题,一个人可能会考虑。
你可以这样称呼它:

func fetchImageData(from url: URL) async throws -> Data {
    try await Task.withTimeout(.seconds(1))  {
        try await URLSession.shared.data(from: url).0
    }
}

所有这些都已经说过了,URLSession/URLRequest都已经有了一个超时参数,所以你也可以使用它,也许:

nonisolated func fetchImageData(from url: URL) async throws -> Data {
    let request = URLRequest(url: url, timeoutInterval: 1)
    return try await URLSession.shared.data(for: request).0
}

相关问题