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
  • 示例:用Actor管理共享状态

示例:用Actor管理共享状态

Actor通过数据隔离和串行访问为共享状态提供了线程安全的保障,前两节介绍了其定义和机制。本节将通过一个具体的实战案例——实现一个多线程访问的库存管理系统——展示如何使用Actor管理共享状态。我们将设计一个库存Actor,处理并发添加和移除操作,并确保数据一致性,最终集成到UI中。通过这个案例,你将掌握Actor在实际开发中的应用技巧。

案例背景

假设我们要开发一个电商应用的库存管理模块,要求:

  • 多线程同时添加或移除商品库存(如用户下单、退货)。
  • 确保库存数量不会出现负值或数据竞争。
  • 在主线程更新UI显示库存状态。
  • 支持异步操作和错误处理。

以下是逐步实现的过程。

实现步骤

1. 定义库存模型和错误类型

首先定义库存项和可能的错误:

struct InventoryItem {
    let id: String
    var quantity: Int
}

enum InventoryError: Error {
    case insufficientStock
    case itemNotFound
}
  • InventoryItem:表示商品及其库存量。
  • InventoryError:处理库存不足或未找到的情况。

2. 创建InventoryActor

设计一个Actor管理库存状态:

actor InventoryActor {
    private var stock: [String: InventoryItem] = [:]
    
    func addItem(id: String, quantity: Int) {
        if let existing = stock[id] {
            stock[id] = InventoryItem(id: id, quantity: existing.quantity + quantity)
        } else {
            stock[id] = InventoryItem(id: id, quantity: quantity)
        }
    }
    
    func removeItem(id: String, quantity: Int) throws -> Int {
        guard let item = stock[id] else {
            throw InventoryError.itemNotFound
        }
        guard item.quantity >= quantity else {
            throw InventoryError.insufficientStock
        }
        let newQuantity = item.quantity - quantity
        stock[id] = InventoryItem(id: id, quantity: newQuantity)
        return newQuantity
    }
    
    func getStock(id: String) -> Int? {
        stock[id]?.quantity
    }
    
    func getAllStock() -> [InventoryItem] {
        Array(stock.values)
    }
}
  • 私有状态:stock字典存储库存。
  • 方法:
    • addItem:添加库存。
    • removeItem:移除库存,检查数量并抛出错误。
    • getStock和getAllStock:查询库存。

3. 测试多线程访问

模拟多线程操作验证线程安全:

Task {
    let inventory = InventoryActor()
    
    // 初始化库存
    await inventory.addItem(id: "book", quantity: 100)
    
    // 并行操作
    await withTaskGroup(of: Void.self) { group in
        // 10个任务添加库存
        for _ in 1...10 {
            group.addTask {
                await inventory.addItem(id: "book", quantity: 5)
            }
        }
        // 10个任务移除库存
        for _ in 1...10 {
            group.addTask {
                do {
                    let _ = try await inventory.removeItem(id: "book", quantity: 3)
                } catch {
                    print("移除失败:\(error)")
                }
            }
        }
    }
    
    let finalStock = await inventory.getStock(id: "book")
    print("最终库存:\(finalStock ?? 0)") // 预期:120 (100 + 10*5 - 10*3)
}
  • 并行任务:20个任务同时操作book库存。
  • 结果:Actor确保操作串行,最终库存准确。

4. 集成到视图控制器

将库存管理整合到UI,支持实时更新:

@MainActor
class StockViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var statusLabel: UILabel!
    private let inventory = InventoryActor()
    private var stockItems: [InventoryItem] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initializeStock()
        simulateOperations()
    }
    
    private func initializeStock() {
        Task {
            await inventory.addItem(id: "book", quantity: 50)
            await inventory.addItem(id: "pen", quantity: 30)
            await updateUI()
        }
    }
    
    private func simulateOperations() {
        Task {
            await withTaskGroup(of: Void.self) { group in
                group.addTask {
                    try? await self.inventory.removeItem(id: "book", quantity: 10)
                    await self.updateUI()
                }
                group.addTask {
                    await self.inventory.addItem(id: "pen", quantity: 5)
                    await self.updateUI()
                }
            }
        }
    }
    
    private func updateUI() async {
        stockItems = await inventory.getAllStock()
        tableView.reloadData()
        statusLabel.text = "库存更新完成"
    }
    
    @IBAction func reduceStock(_ sender: UIButton) {
        Task {
            do {
                let remaining = try await inventory.removeItem(id: "book", quantity: 5)
                statusLabel.text = "移除成功,剩余:\(remaining)"
                await updateUI()
            } catch InventoryError.insufficientStock {
                statusLabel.text = "库存不足"
            } catch {
                statusLabel.text = "错误:\(error)"
            }
        }
    }
}

// UITableViewDataSource
extension StockViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        stockItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "StockCell", for: indexPath)
        let item = stockItems[indexPath.row]
        cell.textLabel?.text = item.id
        cell.detailTextLabel?.text = "数量:\(item.quantity)"
        return cell
    }
}
  • @MainActor:确保UI操作在主线程。
  • 并行操作:模拟多线程添加和移除。
  • 错误处理:用户点击减少库存时显示状态。

运行结果

  • 初始状态:book: 50, pen: 30。
  • 模拟操作后:book: 40, pen: 35(移除10,添加5)。
  • 用户操作:点击减少book库存,成功则更新,失败则提示“库存不足”。

分析与改进

优势

  1. 线程安全:多线程操作库存无竞争,数量始终正确。
  2. 简单性:无需锁或队列,Actor自动隔离。
  3. UI集成:与async/await和MainActor无缝协作。

可改进之处

  • 进度反馈:显示正在处理的请求数。
  • 批量操作:支持一次性添加/移除多个项目:
    func batchUpdate(updates: [(id: String, quantity: Int)]) async {
        for update in updates {
            await addItem(id: update.id, quantity: update.quantity)
        }
    }
    
  • 日志记录:用另一个Actor记录操作历史。

测试建议

  • 并发压力:增加更多并行任务,验证隔离性。
  • 边界情况:尝试移除超过库存的数量,检查错误处理。
  • 取消支持:添加任务取消逻辑。

小结

本节通过库存管理案例展示了Actor在共享状态管理中的强大能力。从设计到UI集成,Actor确保了线程安全和数据一致性。这一实践整合了数据隔离和异步编程的知识,体现了Actor的实际价值。掌握此案例,你将能自信应对并发状态管理。下一章将探讨MainActor与UI线程的结合,进一步完善你的并发技能。


内容说明

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