美文网首页
Swift Concurrency框架之Task和TaskGro

Swift Concurrency框架之Task和TaskGro

作者: zzzworm | 来源:发表于2023-02-22 11:13 被阅读0次

    文章序列:

    Task

    在swift中创建Task很简单,使用Task类的构造函数就可以

    let basicTask = Task {
        let result = await someAsync()
        return result
    }
    

    Task可以返回执行结果,当任务执行出错时也可以抛出异常

    let basicTask = Task {
        // .. perform some work
        throw ExampleError.somethingIsWrong
    }
    
    do {
        print(try await basicTask.value)
    } catch {
        print("Basic task failed with error: \(error)")
    }
    

    我们看一下Task的定义会发现创建Task实际上是通过构造一个闭包来初始化了一个Task实例,在这个闭包里可以执行任意异步函数。

    public init(
        priority: _Concurrency.TaskPriority? = nil, 
        operation: @escaping  () async -> Success)
    
    public init(
        priority: _Concurrency.TaskPriority? = nil, 
        operation: @escaping  () async throws -> Success)
    

    除了 init 构造 Task 之外,Task 还提供 detach 函数来创建一个不一样的 Task:

    public static func detached(
        priority: _Concurrency.TaskPriority? = nil, 
        operation: @escaping  () async -> Success
    ) -> _Concurrency.Task<Success, Failure>
    
    public static func detached(
        priority: _Concurrency.TaskPriority? = nil, 
        operation: @escaping  () async throws -> Success
    ) -> _Concurrency.Task<Success, Failure>
    

    Task.detached 创建的task和 Task.init 创建的Task有所不同的是 Task.detached 创建的task独立运行于当前的Actor,这个Actor的概念我们以后会讲到,你可以先简单理解为线程执行的隔离上下文(保障线程安全用的)。
    Task的取消很简单,调用task的cancel方法就行

    let imageTask = Task { () -> UIImage? in
            let imageURL = URL(string: "https://source.unsplash.com/random")!
            let (imageData, _) = try await URLSession.shared.data(from: imageURL)
            return UIImage(data: imageData)
        }
        // Cancel the image request right away:
        imageTask.cancel()
    

    非结构化任务和结构化任务

    通过Task创建构造的任务,也被称为非结构化的并发任务。与之对应的是添加到TaskGroup的任务被称为结构化Task。
    TaskGroup可以通过add方法将一系列Task添加到一个组里面,TaskGroup会等待所有task都返回后才进行返回。

    let images = await withTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
        let photoURLs = await listPhotoURLs(inGallery: "Amsterdam Holiday")
        for photoURL in photoURLs {
            taskGroup.addTask { await downloadPhoto(url: photoURL) }
        }
    
        var images = [UIImage]()
        for await result in taskGroup {
            images.append(result)
        }
        return images
    }
    

    TaskGroup 也遵循AsyncSequence协议,可以使用reduce方式获取结果

    let images = try await withThrowingTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
        let photoURLs = try await listPhotoURLs(inGallery: "Amsterdam Holiday")
        for photoURL in photoURLs {
            taskGroup.addTask { try await downloadPhoto(url: photoURL) }
        }
    
        return try await taskGroup.reduce(into: [UIImage]()) { partialResult, image in
            partialResult.append(image)
        }
    }
    

    上述例子中的TaskGroup会等待每个任务都执行完成,如果遇到一个任务失败想要提前返回,也可以提前return或者针对ThrowingTaskGroup抛出异常

    let images = try await withThrowingTaskGroup(of: UIImage.self, returning: [UIImage].self) { taskGroup in
        let photoURLs = try await listPhotoURLs(inGallery: "Amsterdam Holiday")
        for photoURL in photoURLs {
            taskGroup.addTask { try await downloadPhoto(url: photoURL) }
        }
    
        var images = [UIImage]()
    
        /// Note the use of `next()`:
        while let downloadImage = try await taskGroup.next() {
            images.append(downloadImage)
        }
        return images
    }
    

    这里调用next方法在结果返回为nil时结束了循环,提前return之前接收的结果集。

    如果要对TaskGroup进行取消,可以调用cancelAll()对添加到组里的每个Task进行取消操作。需要注意的是TaskGroup调用取消操作后,后续添加的task不会自动开始而是自动取消,如果还需要任务进行可以通过addTaskUnlessCancelled()来让任务执行。

    相关文章

      网友评论

          本文标题:Swift Concurrency框架之Task和TaskGro

          本文链接:https://www.haomeiwen.com/subject/aoonkdtx.html