调度组等待永远卡住

Posted

技术标签:

【中文标题】调度组等待永远卡住【英文标题】:Dispatch Group wait stuck forever 【发布时间】:2019-05-29 21:01:10 【问题描述】:

我有一个使用 Alamofire 发出多个 HTTP 请求的函数。我想等待所有这些都完成以返回一个值。但是,它卡在 dispatch.wait()

class func getActionField(fieldid: String, completion: @escaping (_ res: [String: [Double]]) -> Void) 
        var resreturn: [String: [Double]] = ["temperature":[], "humidity":[], "ph":[], "light":[]]
        let dispatch = DispatchGroup()
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/temperatur/" + fieldid, method: .get).responseJSON response in
            resreturn["temperature"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/light/" + fieldid, method: .get).responseJSON response in
            resreturn["light"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/ph/" + fieldid, method: .get).responseJSON response in
            resreturn["ph"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/feuchtigkeit/" + fieldid, method: .get).responseJSON response in
            resreturn["humidity"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        
        dispatch.wait()
        completion(resreturn)
    

【问题讨论】:

【参考方案1】:

假设 getActionField 在主队列上被调用,并且理解 Alamofire 在主队列上调用其完成块(我认为糟糕的设计),你遇到了一个死锁,因为对 wait 的调用是现在阻塞了主队列,无法调用leave

您绝不能使用同一个线程来调用waitleave

最简单的解决方案是将wait 的使用替换为notify

group.notify(queue: DispatchQueue.main) 
    completion(resreturn)

一般情况下,您应该避免使用wait。特别是如果您已经在使用完成处理程序并且不需要等待该方法。

【讨论】:

【参考方案2】:

您已经正确设置了这一切,在所有异步任务完成后使用完成处理程序。唯一的问题是您错误地使用了 DispatchGroup 模式。这是正确的模式(这是伪代码):

let group = DispatchGroup()
group.enter()
queue1.async 
    // ... do task here ...
    group.leave()

group.enter()
queue2.async 
    // ... do task here ...
    group.leave()

group.enter()
queue3.async 
    // ... do task here ...
    group.leave()

// ... more as needed ...
group.notify(queue: DispatchQueue.main) 
    // finished! call completion handler or whatever


【讨论】:

这也是我正在使用的。仅供参考 - group.enter() 调用在另一个之后立即调用,因为闭包立即返回。

以上是关于调度组等待永远卡住的主要内容,如果未能解决你的问题,请参考以下文章

调度与死锁2

调度与死锁2

Jmeter调度器配置

FreeRTOS使用什么样的调度程序?

linux内核的preempt抢占调度,preempt_count抢占保护“锁”

Windows XP线程的调度策略