如何使用Combine限制URLSession并发请求 现有实现是否可行?
问题解答
流程可行性
你这套核心逻辑是可行的,flatMap(maxPublishers: .max(3))本身就是Combine提供的并发控制参数,能够严格限制同时激活的子Publisher数量,也就是最多同时发起3个网络请求,符合你的基础需求。
是否会丢失URL
如果你保留当前的buffer调用,存在丢URL的风险:你设置的whenFull: .dropNewest规则会在缓冲区满时直接丢弃新到的元素。
如果删掉buffer调用则不会丢失任何URL:你使用的数组转换的Publisher是冷发布者,所有元素都是预先确定的,只会根据下游的处理能力按需发送元素,会按顺序处理完全部200个URL,不会主动丢弃。
是否需要buffer()方法
完全不需要。buffer的适用场景是上游为热发布者(比如实时产生的用户事件、推送消息流),这类发布者会主动生成新元素,当上游生成速度远快于下游处理速度时才需要用buffer做缓冲。
你当前的上游是固定的URL数组,属于冷发布者,不会主动生成新元素,天然会适配下游的处理速度,额外加buffer不仅没有作用,反而引入了丢元素的风险。
优化建议
如果你要严格实现「从请求发起,到下载、转模型、调整尺寸、存入缓存的全流程完成后,才发起下一个请求」的要求,可以把耗时的图片调整逻辑也挪到flatMap的闭包内,避免下游处理阻塞导致的请求提前调度,同时可以将耗时操作放到后台队列执行,避免卡主线程:
wayTooManyURLsToHandleAtOnce // this is a `[URL]` .publisher .flatMap(maxPublishers: .max(3)) { url in URLSession.shared .dataTaskPublisher(for: url) .map { (data: Data, _) -> Picture in Picture(from: data) } // 将图片调整逻辑挪到flatMap内,和请求绑定为一个子Publisher .tryCompactMap { resizeImage(picture: $0) } // 捕获单张图片的处理错误,避免单个失败终止整个流 .catch { _ in Empty<ResizedImage, Never>() } } .receive(on: DispatchQueue.main) .sink { completion in // 处理全局完成逻辑 } receiveValue: { resizedImage in self.cache.append(resizedImage) } .store(in: &cancellables)
内容的提问来源于stack exchange,提问作者Aviel Gross
相关产品推荐
相关产品推荐

