gpt4 book ai didi

swift - 为调用异步方法的异步调度队列实现完成处理程序

转载 作者:行者123 更新时间:2023-11-28 06:25:39 25 4
gpt4 key购买 nike

我有一个函数 performSync,它通过一个数组运行,对于这个数组中的每个项目,我正在调用一个函数,该函数本身包含一个异步 alamofire 请求。我需要能够判断这个外部函数何时完成运行 for 循环中的所有函数,所以我需要添加一个完成处理程序。我不确定如何实现这一点。

此外,在我的 for 循环中,我使用了 .userinitiated 来尝试不阻塞 ui 线程,但是线程被阻塞了。我还尝试使用注释掉的并发队列方法,但这也阻止了 UI。

下面的代码:

public class Sync {
public class func onPerformSync(finished: () -> Void){

let syncList = ['Process1', 'Process2', 'Process3']
//let concurrentQueue = DispatchQueue(label: "concurrentQueue", attributes: .concurrent)
for item in syncList {
//concurrentqueue.async
DispatchQueue.global(qos: .background).async {
let className = "appname."+item
let ClassObj = NSClassFromString(className)! as! Helper_Base.Type
ClassObj.doSync()
}
//multiple classes extend Helper_Base and override the doSync func
//I realise there may be a swiftier way to call these doSync methods rather than instantiating from a string and overriding the base class
//doSync and I'd welcome advice on it!
}
//calling finished here is fine if I use a synchronous dispatchQueue but where do i place this line since I need my queue to be asynchronous?
finished()
}
}

open class Process1 : Helper_Base {
override open class func doSync(){
let time = Int64(NSDate().timeIntervalSince1970 * 1000)
repeatBlock(time: time)
}

open class func repeatBlock(time : Int64){
let parameters : [String : String] = [
"x" : time
]
var continueSync : Bool = false
DispatchQueue.global(qos: .background).async {
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default)
.response { response in
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
guard let utf8TextDecoded = utf8Text.fromBase64() else {
return
}

let error = response.error
if error == nil
{
do {
let json = try JSONSerializer.toDictionary(utf8TextDecoded)
let more = json["more"] as! Bool

continueSync = more
}
}
}
if continueSync {
let time = Int64(NSDate().timeIntervalSince1970 * 1000)
DispatchQueue.global(qos: .background).async {
repeatBlock(time: time)
}
}
else{
finishSync()
}
}

}
}

open class func finishSync(){
//other stuff
}
}


Sync.onPerformSync(){
print("we're done syncing")
}

最佳答案

几点观察:

  • 在回答您的主要问题时,如何拥有 finishSync通知它的调用者它已经完成,你可能会重构 doSync采取完成处理程序。这将(因为它正在执行递归网络调用)建议您可以转移到实例方法并保存 completionHandler :
    public class HelperClass {

    private var completionHandler: (() -> Void)?

    open func doSync(item: String, completionHandler: @escaping () -> Void) {
    guard self.completionHandler == nil else { // make sure the existing completionHandler is nil
    fatalError("Either use another instance or let this one finish first")
    }

    self.completionHandler = completionHandler // save the completion handler

    repeatBlock() // start your recursive code
    }

    open func repeatBlock() { // do your recursive stuff
    // do something
    }

    open func finishSync(){
    // other stuff

    completionHandler?() // call the saved completion handler
    completionHandler = nil // and discard it, removing any strong references, if any
    }
    }
  • 这才引出了一个问题,即如何确保顶级 for循环 process1 , process2等,不会同时运行这些循环。坦率地说,您通常希望它同时运行(因为按顺序运行请求会付出巨大的性能损失),但如果您不这样做,您要么必须将其包装在另一个递归请求过程中,要么将整个东西包装在一个异步 Operation自定义子类。
  • 关于您的用户界面被阻止的原因,这不太清楚。如果有的话,您甚至不需要发送 doSync到一些全局队列,因为 Alamofire 是异步的。调度已经异步到后台队列的调用是没有意义的。

    唯一看起来可疑的是来自 repeatBlock 的递归调用。返回 repeatBlock .如果 Alamofire 调用没有异步运行(即它返回缓存结果或有一些错误),理论上你可以在 Alamofire 正在使用的队列上旋转。我建议将递归调用发送到 repeatBlock来自repeatBlockasync , 以避免任何潜在的问题。

    您可以做的另一件事是提供 queue Alamofire 的参数 request ,确保它不使用主队列。留给自己的设备,它在主队列上调用其完成处理程序(这通常非常有用,但可能会在您的场景中导致问题)。我建议尝试提供一个非主队列作为 queue request的参数.

    如果它仍然阻塞,我建议通过 Instruments 的系统跟踪运行它,看看主队列上有哪些阻塞调用。或者您也可以只运行应用程序,在 UI 卡住时暂停它,然后查看主线程的堆栈跟踪,您可能会看到它在哪里阻塞。

    最后,我们必须考虑到主队列的阻塞不依赖于上述代码的可能性。假设您没有遇到 Alamofire 立即调用其完成处理程序的退化情况,上述代码似乎不太可能阻塞主队列。上述诊断应该可以证实这一点,但我可能建议您扩大搜索范围以识别其他会阻塞主队列的事物:
  • 任意 sync从串行队列(例如主队列)到串行队列的调用可能是一个问题。
  • 或者任何锁、信号量或调度组等待也可能是候选对象。
  • 您的路径既不递归调用 repeatBlock也不要调用finishSync ...你确定主队列被阻塞了,这不仅仅是它从不调用 finishSync 的问题吗?在某些执行路径中。

  • 底线,确保问题实际上在于阻塞上述代码中的主线程。我怀疑它可能不会。
    最后以一些不请自来的建议结束,并且无意冒犯,我们应该承认,在这一系列网络请求中存在一丝代码异味。如果您想返回更多数据,请更改 Web 服务 API 以返回更多数据……这种重复、系统地获取额外数据(尤其是按顺序完成时)效率极低。网络延迟将使整体性能(即使在您解决了这个主队列阻塞问题之后)真正受到影响。

    关于swift - 为调用异步方法的异步调度队列实现完成处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41978206/

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