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

能否实现同步执行但不阻塞主线程的URLSession调用?

实现方案

核心思路

完全基于Swift原生Concurrency异步体系实现,替换原有的阻塞式Semaphore/Thread.sleep逻辑,既保证串行执行、间隔≥4秒的要求,也不会阻塞主线程。

适配约束说明

  • 系统兼容性:Swift Concurrency原生支持macOS Monterey及以上版本,满足系统要求
  • 强制使用指定异步语法:直接使用let (data, response) = try await session.data(for: request)标准异步调用写法
  • 间隔控制:每次任务启动时记录时间戳,任务执行完成后计算已耗时,不足4秒的部分通过Task.sleep非阻塞等待补全,从根源避免触发服务端间隔过短错误

完整实现代码

import Foundation

// 定义请求结果结构体,方便后续按顺序合并
struct RequestResult {
    let text: String
    let data: Data
    let response: URLResponse
    let error: Error?
}

/// 单个请求异步实现
func requestSingle(authToken: String, transformedText: String) async throws -> RequestResult {
    let targetURL = "https://..."
    let urlconfig = URLSessionConfiguration.ephemeral
    urlconfig.timeoutIntervalForRequest = 120
    urlconfig.timeoutIntervalForResource = 120
    let urlSession = URLSession(configuration: urlconfig)
    
    guard let url = URL(string: targetURL),
          let httpBodyData = transformedText.data(using: .utf8) else {
        throw NSError(domain: "RequestError", code: -1, userInfo: [NSLocalizedDescriptionKey: "参数错误"])
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.httpBody = httpBodyData
    request.addValue("Token " + authToken, forHTTPHeaderField: "Authorization")
    
    // 使用要求的异步调用语法
    let (data, response) = try await urlSession.data(for: request)
    return RequestResult(text: transformedText, data: data, response: response, error: nil)
}

/// 批量串行执行请求,自动控制间隔、按顺序返回结果
func batchExecuteRequests(authToken: String, sentences: [String]) async -> [RequestResult] {
    var results: [RequestResult] = []
    let minInterval: TimeInterval = 4
    var lastTaskStartTime: Date?
    
    for sentence in sentences {
        // 前置校验:距离上一次任务启动不足4秒则补足间隔
        if let lastStart = lastTaskStartTime {
            let elapsed = Date().timeIntervalSince(lastStart)
            if elapsed < minInterval {
                try? await Task.sleep(nanoseconds: UInt64((minInterval - elapsed) * 1_000_000_000))
            }
        }
        
        let currentStart = Date()
        lastTaskStartTime = currentStart
        
        // 执行请求
        do {
            let result = try await requestSingle(authToken: authToken, transformedText: sentence)
            results.append(result)
        } catch {
            results.append(RequestResult(text: sentence, data: Data(), response: HTTPURLResponse(), error: error))
        }
        
        // 后置校验:任务执行完成后距离启动不足4秒则补足间隔
        let taskElapsed = Date().timeIntervalSince(currentStart)
        if taskElapsed < minInterval {
            try? await Task.sleep(nanoseconds: UInt64((minInterval - taskElapsed) * 1_000_000_000))
        }
    }
    return results
}

// 调用示例,不会阻塞主线程
func testServerRequest() {
    let sentences = ["Example Sentence1","Example Sentence2","Example Sentence3"]
    let authToken = "你的授权Token"
    
    // 异步启动任务,主线程可继续响应UI交互
    Task {
        let allResults = await batchExecuteRequests(authToken: authToken, sentences: sentences)
        // 所有任务执行完成,此处直接使用按顺序合并后的结果
        print("所有请求执行完成,共\(allResults.count)条结果")
    }
}

非阻塞原理说明

所有等待逻辑使用的Task.sleep是Swift Concurrency提供的非阻塞等待API,执行时只会挂起当前Task的执行权,不会阻塞当前线程,主线程可以正常处理UI交互等其他操作,完全符合非阻塞要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:24:04