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

Swift中sensMessage函数无法串行执行的问题排查与修复

问题分析

你当前的代码没实现预期的串行效果,核心原因是:

  • 串行队列serialQueue里的async任务仅负责触发网络请求,而网络请求本身是异步执行的。当队列内的任务调用完self.sessionManager.request()后,这个任务就已执行完毕,串行队列会立刻调度下一个任务,导致所有"Start"日志一次性输出,完全没等上一个请求的回调完成就启动了下一个请求。
修复方案

要实现真正的串行执行(前一个请求回调触发后再启动下一个),需要让串行队列中的任务等待网络请求的回调完成后再结束,以下提供两种可行方案:

方案一:使用DispatchSemaphore阻塞等待

private let serialQueue = DispatchQueue(label: "com.yourapp.messageQueue")
let sessionManager = Session(configuration: configuration, rootQueue: serialQueue, interceptor: self)

func sendMessage(message: Message, completion: @escaping (Result) -> Void) {
    serialQueue.async { [weak self] in
        guard let self = self else { return }
        
        print("Start async queue method: \(message.objectID)")
        
        // 自定义前置逻辑
        // SOME LOGIC
        
        // 创建初始值为0的信号量,用于阻塞当前队列任务
        let semaphore = DispatchSemaphore(value: 0)
        
        self.sessionManager.request()
            .response(queue: .global()) { response in 
                // 回调队列不能用serialQueue,否则会因队列线程阻塞导致死锁
                print("Finish async queue method: \(message.objectID)")
                semaphore.signal() // 信号量+1,唤醒等待的线程
                // 建议切回主线程执行completion,避免UI操作异常
                DispatchQueue.main.async {
                    completion(.success)
                }
            }
        
        semaphore.wait() // 信号量-1,当前线程阻塞,直到收到signal信号
    }
}

方案二:任务队列串行调度(无阻塞更优雅)

通过维护一个任务列表,每次仅执行列表中的第一个任务,完成后自动启动下一个,避免线程阻塞:

private let serialQueue = DispatchQueue(label: "com.yourapp.messageQueue")
private var pendingMessages: [(Message, (Result) -> Void)] = []
let sessionManager = Session(configuration: configuration, rootQueue: serialQueue, interceptor: self)

func sendMessage(message: Message, completion: @escaping (Result) -> Void) {
    serialQueue.async { [weak self] in
        guard let self = self else { return }
        // 将任务加入待执行队列
        self.pendingMessages.append((message, completion))
        // 只有当队列中只有当前任务时,才启动执行(避免重复触发)
        guard self.pendingMessages.count == 1 else { return }
        self.processNextMessage()
    }
}

private func processNextMessage() {
    guard !pendingMessages.isEmpty else { return }
    let (message, completion) = pendingMessages.removeFirst()
    
    print("Start async queue method: \(message.objectID)")
    
    // 自定义前置逻辑
    // SOME LOGIC
    
    self.sessionManager.request()
        .response(queue: .global()) { response in
            print("Finish async queue method: \(message.objectID)")
            DispatchQueue.main.async {
                completion(.success)
            }
            // 回到串行队列,启动下一个任务
            self.serialQueue.async {
                self.processNextMessage()
            }
        }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:28:26