gpt4 book ai didi

ios - 如何限制for循环中的网络调用次数?

转载 作者:行者123 更新时间:2023-12-01 15:42:53 24 4
gpt4 key购买 nike

我在服务器上为每个用户都有一些对象,我必须全部获取它们。我首先从服务器获取对象计数,以计算我必须以 30 个为一组进行网络调用的数量。假设有 2000 个对象,那么我必须进行的调用数量为 2000/30 = 67。我为第一次调用设置了偏移量 = 0 和限制 = 29,然后将偏移量和限制值都增加 30,然后进行第二次调用,依此类推。问题是,如果我在 for 循环中同时发送 8 个以上的调用,则调用开始失败,即使我重试,它也会继续失败。我正在使用 Alamofire 向服务器发送发布请求。我注意到如果我并行发送 8 个请求,一切似乎都很好。我如何确保并行进行 8 个调用,并且当所有 8 个调用都完成后,再向服务器发送 8 个调用。

这是一段代码:

 let count = Double(totalTransactionsCount)
//The maximum amount of transactions to fetch in one call.
//let maxLimit = 30
let calls = Int(ceil(count/Double(maxLimit)))

for call in 1...calls {
print("Calling call \(call) with offset:\(offset) to limit:\(limit)")
callFetchTransactionWith(offset, limit)

offset += maxLimit
limit += maxLimit
}


fileprivate func callFetchTransactionWith(_ offset: Int, _ limit: Int, _ callCountPercentage: Double, _ calls: Int) {
TransactionsModel.reportTransactions(offset: offset, limit: limit ,success: { (transactions) in
ACTIVITYCALL += 1
self.currentSyncingProgress = self.currentSyncingProgress + CGFloat(callCountPercentage)
Utility.logger(log: "\(self.currentSyncingProgress)", message: "Activity Increment Progress")
if ACTIVITYCALL == calls {
TransactionsModel.assignSequenceNumbers()
self.didCompleteProgressAndSync(duration: 2.0)
return
} else {
self.updateProgressBar(value: self.currentSyncingProgress)
}
}, failure: { (response, statusCode) in
print(response,statusCode)
self.callFetchTransactionWith(offset, limit, callCountPercentage, calls)
})
}


static func reportTransactions(offset:Int,limit:Int,
success:@escaping ( _ model: [TransactionsModel] ) -> Void,
failure:@escaping APIClient.FailureHandler) {

let params:Parameters = [
"offset":offset,
"limit":limit
]

let headers:[String:String] = [
"X-Auth-Token":Singleton.shared.token
]

if !Connectivity.isConnectedToInternet {
Constants.UIWindow?.showErrorHud(text: AppString.internetUnreachable)
return
}

APIClient.shared().requestPost(endpoint: Route.reportTransactions, params: params, headers: headers, success: { (response) in
guard
let data = response as? [String:Any],
let transactions = data["transactions"] as? [[String : Any]]
else {return}

let transactionModels = Mapper<TransactionsModel>().mapArray(JSONArray: transactions)
TransactionsModel.save(transactions: transactionModels)

success(transactionModels)
}) { (response, status) in
print(response,status)
failure(response,status)
}
}

最佳答案

信号量

这看起来是信号量的一个很好的用例。

enter image description here
积分:https://unsplash.com/photos/5F04PN6oWeM

让我向您展示如何使用 Playground 执行此操作,以便您可以在本地运行此解决方案,然后将其导入到您的项目中。

操场

首先创建一个新的空 Playground 页面和这 3 行,以便导入所需的库并启用并发。

import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

Once you decide to move this solution to your project you need only the import Foundation line.



内容

现在让我们定义以下 3 个常量。

并发调用
这是您要执行的并发调用数。
let concurrentCalls = 8

信号量
该信号量将允许执行不超过 8 个线程。当第 9 个线程请求访问时,它会等待 8 个线程中的一个运行完成。
let semaphore = DispatchSemaphore(value: concurrentCalls)

后台队列
我们将使用这个队列异步调度所有调用。
let backgroundQueue = DispatchQueue(label: "Background queue")

fetchData(完成:

此函数是对远程 API 调用的模拟。它只等待 3 秒,然后调用完成并传递表示结果的“🎁”字符串。
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
completion("🎁")
}
}

fetchAll(完成:)

现在我们处于解决方案的核心。
func fetchAll(completion: @escaping ([String]) -> Void) {
// 1
let storageQueue = DispatchQueue(label: "Serial queue")

var results = [String]()
let totalNumberOrCalls = 20

for i in 0..<totalNumberOrCalls {
backgroundQueue.async {
semaphore.wait()
fetchData { result in
storageQueue.async {
results.append(result)
if i == totalNumberOrCalls - 1 {
completion(results)
}
}
// 2
semaphore.signal()
}
}
}
}

它是如何工作的?

我们有一个值设置为 8 的信号量。

每次我们想要执行网络调用时,我们都会询问信号量是否可以开始调用
// 1
semaphore.wait()

如果信号量持有一个值 大于 0 ,那么它 允许 我们的远程调用并递减它的值。

否则如果信号量 持有 0 那么网络电话是 未执行 ,而是穿上 等待 直到前一个调用结束。

一旦网络调用结束,我们就调用
// 2
semaphore.signal

这样信号量值是 增加 1 并且确实允许执行另一个等待调用。

测试

现在我们调用
fetchAll { results in
print(results)
}

fetchData 的并发调用不会超过 8 个一旦所有的调用完成,结果就会被打印出来
["🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁", "🎁"]

结论

希望这会有所帮助,如果您想了解更多详细信息,请查看我谈论信号量的答案 https://stackoverflow.com/a/51816661/1761687

关于ios - 如何限制for循环中的网络调用次数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59802079/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com