Swift:Simple DispatchQueue无法运行且无法正确通知

时间:2018-11-29 16:19:11

标签: swift grand-central-dispatch

我做错了什么?在操场上,它可以正常运行。但是,一旦我将其部署到iOS模拟器上,它就会返回错误的顺序。

@objc func buttonTapped(){

    let group = DispatchGroup()
    let dispatchQueue = DispatchQueue.global(qos: .default)

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print(" \(i)")  
        }
        group.leave()
    }

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("❌ \(i)")
        }
        group.leave()
    }

    group.notify(queue: DispatchQueue.main) {
        print("jobs done by group")
    }   
}

控制台输出:

ios-Simulator playground

我不明白。

2 个答案:

答案 0 :(得分:1)

您还应该将group.leave()语句放入dispatchQueue.async块中,否则它将在异步块完成执行之前同步执行。

@objc func buttonTapped(){

    let group = DispatchGroup()
    let dispatchQueue = DispatchQueue.global(qos: .default)

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print(" \(i)")  
            group.leave()
        }
    }

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("❌ \(i)")
            group.leave()
        }
    }

    group.notify(queue: DispatchQueue.main) {
        print("jobs done by group")
    }   
}

答案 1 :(得分:1)

Dávid said一样,正确使用的调度组仅确保通知在所有任务完成后发生,您可以通过从调度的块内调用leave来实现,正如他向您展示的那样。或者,由于您分派的任务本身是同步的,因此您不必手动enterleave group,但是可以使用{{ 1}}方法:

group

在调用某些异步方法时使用asynclet group = DispatchGroup() let queue = DispatchQueue.global(qos: .default) for i in 1...4 { queue.async(group: group) { print(" \(i)") } } for i in 1...4 { queue.async(group: group) { print("❌ \(i)") } } group.notify(queue: .main) { print("jobs done by group") } ,但是对于这些group.enter()语句,您可以仅使用async(group:execute:),如上所示。

现在,我们已经解决了“按组完成的工作”块不等待所有分派的任务的问题。但是,由于您正在将所有这些分派都发送到并发队列(所有全局队列都是并发队列),因此无法保证将按照您请求的顺序执行任务。它们以严格的FIFO方式排队,但是由于它们是并发的,因此您无法保证何时击中相应的group.leave()语句。

如果需要它来按顺序打印消息,则必须使用串行队列。例如,如果您创建自己的队列,则在没有.concurrent属性的情况下,以下内容将创建一个串行队列:

print

如果您使用此串行队列运行上述代码,您将看到所需内容:

  

1
   2
   3
   4
  ❌1
  ❌2
  ❌3
  ❌4
  小组完成的工作

但是,再一次,如果您使用的是串行队列,则print完全没有必要(您可以在串行队列的末尾添加“ completion”任务作为另一个调度任务) 。我仅展示了使用串行队列来避免将八个任务分派到并发队列的竞争情况。