GCD函数乱序调用

问题描述:

我不明白为什么下面的代码被乱序调用。它只是为了公开它们被调用的顺序而写的。这很重要,因为我正在使用这些Web服务调用,它们应该彼此等待,而他们不是。所以,这可能只是我对如何使用GCD的概念。GCD函数乱序调用

var group: dispatch_group_t = dispatch_group_create() 
var groupTwo: dispatch_group_t = dispatch_group_create() 
var queue: dispatch_queue_t = dispatch_get_main_queue() 

dispatch_group_notify(groupTwo, queue) {() -> Void in 
    print("3rd") // Should be called 3rd 
} 

dispatch_group_enter(group) 
    print("1st") // Should be called 1st 
dispatch_group_leave(group) 

dispatch_group_notify(group, queue) {() -> Void in 
    dispatch_group_enter(groupTwo) 
      print("2nd") // Should be called 2nd 
    dispatch_group_leave(groupTwo) 
} 

这是命令它打印在:

1st 
3rd 
2nd 

为什么是顺序错了吗?不应该3rd只叫一次dispatch_group_leave(groupTwo)叫?为什么事先被调用?我认为这是dispatch_group_notify()被用于。

编辑:对不起,我只是修复了组名。起初忘了编辑一些。

+0

,你做'dispatch_group_enter(groupTwo)块,如果'groupTwo'为空,并在第一时间之后执行的第一个'dispatch_group_notify'检查'版画“第三“一旦发现它是。 – dan

+0

我没有想到'dispatch_group_notify'甚至会在dispatch_group_leave之前被调用。有没有更好的方法来完成我想要做的事情? – chicobermuda

+0

这是不是很清楚你想做什么。我假设你为了这个问题抽象了所有的细节,但是很难说出你应该做什么。 – dan

dispatch_group_notify(groupTwo, queue) {() -> Void in 
    print("3rd") // Should be called 3rd 
} 

dispatch_group_notify将在组为空时将第一个块提交给队列。最初,该组是空的。因此,它将异步提交给主队列。

这里

dispatch_group_enter(group) 
    print("1st") // Should be called 1st 
dispatch_group_leave(group) 

您有效地打印到控制台上的主队列 - 此打印

1st 

这里

dispatch_group_notify(group, queue) {() -> Void in 
    dispatch_group_enter(groupTwo) 
      print("2nd") // Should be called 2nd 
    dispatch_group_leave(groupTwo) 
} 

你异步提交其被排队的第二块在第一块之后。

现在,第一块执行,打印

3rd 

最后,第二块打印:

2nd 

这听起来像你需要等待两个或多个远程调用的结果然后才能发出最终的远程呼叫。比方说,你有这些参数,这将通过远程调用来填充两个属性:

var a:String? = nil // populated asynchronously 
var b:String? = nil // populated asynchronously 

然后,假设你的远程调用是这样的:

func getParameterA(completionHandler:(String) -> Void) { 
    print("Getting parameter A") 
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { 
     NSThread.sleepForTimeInterval(0.2) 
     completionHandler("A") 
     print("Got parameter A") 
    } 
} 

func getParameterB(completionHandler:(String) -> Void) { 
    print("Getting parameter B") 
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { 
     NSThread.sleepForTimeInterval(0.1) 
     completionHandler("B") 
     print("Got parameter B") 
    } 
} 

func getResult(a:String, b:String, completionHandler:(String) -> Void) { 
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { 
     NSThread.sleepForTimeInterval(0.05) 
     completionHandler("This is the result of \(a) and \(b)") 
    } 
} 

在现实中,他们将远程调用而不是睡在后台线程上。

然后,你的代码来填充ab看起来就像这样:

// the blocks in the parameter group are responsible for setting a and b 
let parameterGroup = dispatch_group_create() 
dispatch_group_enter(parameterGroup) 
getParameterA() { parameter in 
    // set the value of a asynchronously 
    self.a = parameter 
    dispatch_group_leave(parameterGroup) 
} 
dispatch_group_enter(parameterGroup) 
getParameterB() { parameter in 
    // set the value of b asynchronously 
    self.b = parameter 
    dispatch_group_leave(parameterGroup) 
} 

最后,你可以用dispatch_group_notify定义最终完成处理程序只执行一次,有没有更多的任务parameterGroup

let finalGroup = dispatch_group_create() 
dispatch_group_enter(finalGroup) 
dispatch_group_notify(parameterGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 
    self.getResult(self.a!, b:self.b!) { result in 
     print("-- \(result)") 
     dispatch_group_leave(finalGroup) 
    } 
} 
dispatch_group_wait(finalGroup, DISPATCH_TIME_FOREVER) 

finalGroup不是严格必要的,但我需要它来得到范例在XCTest内工作。

输出将是这样的:

Getting parameter A 
Getting parameter B 
Got parameter B 
Got parameter A 
-- This is the result of A and B