Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 示例:批量下载图片并处理结果

示例:批量下载图片并处理结果

Task Group的并行执行能力在批量处理任务时尤为强大,前两节介绍了其基本用法和并行原理。本节将通过一个完整的实战案例——批量下载图片并处理结果——展示如何在Swift中使用Task Group实现高效的异步流程。我们将设计一个图片下载模块,处理下载结果并更新UI,同时应对错误和性能需求,帮助你将结构化并发的知识转化为实际代码。

案例背景

假设我们要开发一个图片浏览应用,需要从多个URL下载图片,应用滤镜后显示在界面上。要求:

  • 并行下载图片,缩短总耗时。
  • 处理下载和滤镜应用的错误。
  • 在主线程更新UI。
  • 支持取消操作。

以下是逐步实现的过程。

实现步骤

1. 定义模型和错误类型

首先定义图片处理相关类型:

struct ProcessedImage {
    let id: Int
    let image: UIImage
}

enum ImageError: Error {
    case downloadFailed(Error)
    case invalidData
    case processingFailed
}
  • ProcessedImage:包含ID和处理后的图片。
  • ImageError:覆盖下载和处理中的异常。

2. 实现下载和处理函数

设计异步函数执行核心逻辑:

func downloadImage(from url: URL) async throws -> Data {
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}

func processImage(data: Data, id: Int) async throws -> ProcessedImage {
    guard let image = UIImage(data: data) else { throw ImageError.invalidData }
    try? await Task.sleep(nanoseconds: 500_000_000) // 模拟滤镜处理
    return ProcessedImage(id: id, image: image)
}
  • downloadImage:下载原始数据。
  • processImage:将数据转为图片并模拟处理。

3. 使用Task Group批量处理

创建一个函数并行下载并处理图片:

func fetchAndProcessImages(from urls: [URL]) async throws -> [ProcessedImage] {
    try await withThrowingTaskGroup(of: ProcessedImage.self) { group in
        for (index, url) in urls.enumerated() {
            group.addTask {
                let data = try await downloadImage(from: url)
                return try await processImage(data: data, id: index)
            }
        }
        
        var results: [ProcessedImage] = []
        for try await image in group {
            results.append(image)
        }
        return results.sorted { $0.id < $1.id } // 按ID排序
    }
}
  • withThrowingTaskGroup:支持错误抛出。
  • addTask:并行执行下载和处理。
  • 结果按原始顺序排序。

4. 集成到视图控制器

将逻辑整合到UI更新中,支持取消:

@MainActor
class GalleryViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var statusLabel: UILabel!
    private var images: [ProcessedImage] = []
    private var downloadTask: Task<Void, Never>?

    override func viewDidLoad() {
        super.viewDidLoad()
        startDownload()
    }

    private func startDownload() {
        let urls = [
            URL(string: "https://example.com/image1.jpg")!,
            URL(string: "https://example.com/image2.jpg")!,
            URL(string: "https://example.com/image3.jpg")!
        ]
        
        downloadTask = Task {
            statusLabel.text = "下载中..."
            do {
                images = try await fetchAndProcessImages(from: urls)
                collectionView.reloadData()
                statusLabel.text = "完成"
            } catch ImageError.downloadFailed(let error) {
                statusLabel.text = "下载失败:\(error.localizedDescription)"
            } catch ImageError.invalidData {
                statusLabel.text = "图片数据无效"
            } catch {
                statusLabel.text = "未知错误:\(error)"
            }
        }
    }

    @IBAction func cancelDownload(_ sender: UIButton) {
        downloadTask?.cancel()
        statusLabel.text = "已取消"
    }
}

// UICollectionViewDataSource
extension GalleryViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        images.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCollectionViewCell
        cell.imageView.image = images[indexPath.item].image
        return cell
    }
}
  • @MainActor:确保UI操作在主线程。
  • Task:封装整个流程,支持取消。
  • 错误分类型显示用户友好提示。

5. 添加取消检查

在任务中响应取消:

func fetchAndProcessImages(from urls: [URL]) async throws -> [ProcessedImage] {
    try await withThrowingTaskGroup(of: ProcessedImage.self) { group in
        for (index, url) in urls.enumerated() {
            group.addTask {
                try Task.checkCancellation() // 检查取消
                let data = try await downloadImage(from: url)
                try Task.checkCancellation() // 再次检查
                return try await processImage(data: data, id: index)
            }
        }
        
        var results: [ProcessedImage] = []
        for try await image in group {
            results.append(image)
        }
        return results.sorted { $0.id < $1.id }
    }
}
  • checkCancellation():若任务取消,抛出CancellationError。

运行结果

  • 成功时:三张图片并行下载和处理,约1.5秒后显示(下载+处理时间重叠)。
  • 失败时:显示错误信息,如“下载失败:timeout”。
  • 取消时:点击取消按钮,状态变为“已取消”,未完成任务停止。

分析与改进

优势

  1. 高效并行:总耗时接近最慢单任务时间。
  2. 错误集中:统一捕获并处理异常。
  3. 结构清晰:任务组管理生命周期,避免手动跟踪。

可改进之处

  • 进度反馈:显示已完成任务数:
    for try await image in group {
        results.append(image)
        await MainActor.run { statusLabel.text = "已完成\(results.count)/\(urls.count)" }
    }
    
  • 重试机制:对失败任务重试。
  • 缓存支持:保存成功下载的图片。

测试建议

  • 网络中断:关闭网络测试错误处理。
  • 取消操作:下载中取消,确保任务停止。
  • 性能评估:增加URL数量,观察并行效果。

小结

本节通过批量下载图片的案例,展示了Task Group在并行执行和结果处理中的强大能力。从任务设计到UI集成,再到取消支持,这一实践整合了结构化并发的核心概念。掌握此案例,你将能灵活应对多任务异步场景。本章回顾了结构化并发的优势,下一章将探讨非结构化并发,与之对比完善你的并发知识体系。


内容说明

  • 结构:从背景到实现步骤,再到分析和总结。
  • 代码:完整案例覆盖模型、下载、UI和取消,突出实用性。
  • 语气:实践性且深入,适合技术书籍核心章节。
  • 衔接:承接前两节(Task Group基础和并行),预告后续(非结构化并发)。
Last Updated:: 3/5/25, 9:43 AM