能否实现同步执行但不阻塞主线程的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
相关产品推荐
相关产品推荐

