GCD功能无序调用

时间:2015-11-09 19:15:52

标签: ios multithreading swift synchronization grand-central-dispatch

我无法弄清楚为什么以下代码无序调用。它只是为了暴露他们所调用的顺序而不按顺序编写。这很重要,因为我将这些用于互相等待的Web服务调用,但他们并没有。所以,它可能只是我对如何使用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()的用途。

编辑:对不起,我刚刚修改了组名。最初忘了编辑一些。

2 个答案:

答案 0 :(得分:1)

听起来您需要等待两个或更多远程呼叫的结果才能发出最终远程呼叫。假设您有两个参数属性,这些属性将由远程调用填充:

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

答案 1 :(得分:0)

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