You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

URLSession异步调用并发问题:上传服务重复执行与死锁排查

解决上传服务并发重复调用与死锁问题

问题根源分析

  • 每次创建UploadService实例都会启动独立异步任务执行上传,多实例同时运行导致后端重复接收请求。
  • 使用NSLock时,async/await的异步上下文会切换执行线程:锁在await阶段持续被持有,后续任务阻塞等待锁资源;当前任务在await完成后可能切换到其他线程,导致锁无法正常释放或执行流程被阻塞,最终无法进入success/failure分支。

解决方案:用Actor实现并发安全控制

Swift的Actor是原生并发安全原语,能自动保证内部方法串行执行,搭配单例设计可彻底解决重复调用与死锁问题。

修改后的代码

// 用Actor保证内部逻辑串行执行,天然实现并发安全
actor UploadService {
    // 全局唯一单例,避免外部重复创建实例
    static let shared = UploadService()
    
    // 私有化初始化方法,禁止外部实例化
    private init() {}
    
    func uploadData() async {
        let context = PersistentContainer.shared.newBackgroundContext()
        // 确保Core Data操作在其专属线程执行,避免线程安全问题
        context.performAndWait {
            guard let uploadedThing = Upload.coreDataFetch(in: context) else {
                return
            }
            
            Task {
                // 注意:此处原代码存在命名冲突,建议将网络请求类重命名为UploadRequest
                let request = UploadRequest(configuration: networkConfiguration)
                let result = await request.uploadList(uploadedThing)
                
                switch result {
                case .success:
                    print("success")
                case .failure(let error as NSError):
                    print("error happened: \(error.localizedDescription)")
                }
            }
        }
    }
}

class UploadExtension {
    func createUploadService() {
        for i in 0...4 {
            // 调用单例的上传方法,即使循环多次也只会串行执行任务
            Task {
                await UploadService.shared.uploadData()
            }
        }
    }
}

关键改动说明

  1. Actor化改造:将UploadService声明为Actor,Swift自动保证其所有方法串行执行,无需手动加锁,从根源避免并发冲突。
  2. 单例设计:通过私有化初始化+全局单例,确保外部无法创建多个实例,彻底消除多实例并发触发上传的问题。
  3. Core Data线程安全:使用context.performAndWait包裹Core Data查询操作,确保数据访问在其专属线程执行,规避线程安全风险。
  4. 调用逻辑调整:循环中直接调用单例的uploadData方法,多次调用会被Actor串行处理,不会重复触发后端请求。

额外注意事项

  • 原代码中UploadService(configuration: networkConfiguration)存在命名冲突,建议将负责网络请求的类重命名(如UploadRequest),避免与Actor类混淆。
  • 若需支持上传任务取消,可在Actor中存储当前Task实例,新增取消方法实现任务终止逻辑。
  • 如需重试机制,可在failure分支中添加重试逻辑,借助Actor的串行特性保证重试任务有序执行。

内容的提问来源于stack exchange,提问作者atalayasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 21:45:34