Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios GCD中的并发队列与串行队列_Ios_Multithreading_Concurrency_Grand Central Dispatch - Fatal编程技术网

Ios GCD中的并发队列与串行队列

Ios GCD中的并发队列与串行队列,ios,multithreading,concurrency,grand-central-dispatch,Ios,Multithreading,Concurrency,Grand Central Dispatch,我很难完全理解GCD中的并发队列和串行队列。我有一些问题,希望有人能及时清楚地回答我 我读到串行队列是为了一个接一个地执行任务而创建和使用的。但是,如果: 我创建了一个串行队列 我使用dispatch\u async(在我刚刚创建的串行队列上)三次来调度三个块A、B、C 将执行三个块: 顺序为A、B、C,因为队列是串行的 或 并发(同时在parralel线程上),因为我使用了异步调度 我读到我可以在并发队列上使用dispatch\u sync,以便一个接一个地执行块。在这种情况下,为什么

我很难完全理解GCD中的并发队列和串行队列。我有一些问题,希望有人能及时清楚地回答我

  • 我读到串行队列是为了一个接一个地执行任务而创建和使用的。但是,如果:

    • 我创建了一个串行队列
    • 我使用
      dispatch\u async
      (在我刚刚创建的串行队列上)三次来调度三个块A、B、C
    将执行三个块:

    • 顺序为A、B、C,因为队列是串行的

    • 并发(同时在parralel线程上),因为我使用了异步调度
  • 我读到我可以在并发队列上使用
    dispatch\u sync
    ,以便一个接一个地执行块。在这种情况下,为什么还要存在串行队列,因为我可以始终使用并发队列,在该队列中,我可以同步调度任意数量的块

    谢谢你的解释


  • 一个简单的例子:您有一个需要一分钟才能执行的块。您可以从主线程将其添加到队列中。让我们看看这四个案例

    • 异步并发:代码在后台线程上运行。控件立即返回到主线程(和UI)。块不能假定它是该队列上运行的唯一块
    • 异步-串行:代码在后台线程上运行。控件立即返回到主线程。该块可以假定它是该队列上运行的唯一块
    • sync-concurrent:代码在后台线程上运行,但主线程等待它完成,从而阻止对UI的任何更新。该块不能假定它是该队列上运行的唯一块(我可以在几秒钟之前使用async添加另一个块)
    • sync-serial:代码在后台线程上运行,但主线程等待它完成,从而阻止对UI的任何更新。该块可以假定它是该队列上运行的唯一块

    显然,对于长时间运行的进程,您不会使用后两种方法中的任何一种。通常,当您试图从另一个线程上运行的某个内容更新UI(始终在主线程上)时,您会看到它。

    以下是我做的几个实验,以使我了解这些
    串行
    并发
    队列和
    大型中央调度

     func doLongAsyncTaskInSerialQueue() {
    
       let serialQueue = DispatchQueue(label: "com.queue.Serial")
          for i in 1...5 {
            serialQueue.async {
    
                if Thread.isMainThread{
                    print("task running in main thread")
                }else{
                    print("task running in background thread")
                }
                let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imgURL)
                print("\(i) completed downloading")
            }
        }
    }
    
    在GCD中使用异步时,任务将在不同的线程(主线程除外)中运行。异步意味着执行下一行不等待块执行,这将导致非阻塞主线程和主队列。 由于它是串行队列,所以所有任务都按照它们添加到串行队列的顺序执行。串行执行的任务总是由与队列关联的单个线程一次执行一个

    在GCD中使用同步时,任务可能会在主线程中运行。Sync在给定队列上运行一个块并等待它完成,这将导致阻塞主线程或主队列。由于主队列需要等待,直到分派的块完成,主线程将可用于处理来自主队列以外的队列的块。因此,在后台队列上执行的代码可能实际上正在主线程上执行 由于它是串行队列,所以所有操作都是按照添加顺序(FIFO)执行的

    在GCD中使用异步时,任务将在后台线程中运行。异步意味着执行下一行不等待块执行,这将导致非阻塞主线程。 请记住,在并发队列中,任务是按照添加到队列的顺序处理的,但不同的线程连接到队列 队列记住,他们不应该按顺序完成任务 它们被添加到队列中。每次任务的顺序都不同 线程是自动创建的,任务是并行执行的。超过 如果达到(maxConcurrentOperationCount),则某些任务将正常运行 作为串行,直到线程空闲

    在GCD中使用同步时,任务可能会在主线程中运行。Sync在给定队列上运行一个块并等待它完成,这将导致阻塞主线程或主队列。由于主队列需要等待,直到分派的块完成,主线程将可用于处理来自主队列以外的队列的块。因此,在后台队列上执行的代码可能实际上正在主线程上执行。 由于其并发队列,任务可能不会按照添加到队列中的顺序完成。但对于同步操作,它确实可以,尽管它们可能由不同的线程处理。因此,它的行为就像这是串行队列一样

    以下是这些实验的总结

    请记住,使用GCD时,您只是将任务添加到队列并从该队列执行任务。队列根据操作是同步还是异步,在主线程或后台线程中调度任务。队列类型包括串行、并发和主调度队列。默认情况下,您执行的所有任务都是从主调度队列完成的。应用程序已经有四个预定义的全局并发队列可供使用,还有一个主队列(DispatchQueue.Main)。您也可以手动创建自己的队列并从该队列执行任务

    UI相关的任务应始终通过将任务分派到主队列从主线程执行。简写实用程序为
    DispatchQueue.main.sync/async
    ,而与网络相关的/繁重的操作应始终异步执行,无论您使用的是主线程还是后台线程

    编辑: 但是,在某些情况下,您需要在后台线程中同步执行网络调用操作,而不冻结UI(例如,刷新OAuth令牌并等待成功与否)。您需要将该方法包装在异步操作中
    func doLongSyncTaskInSerialQueue() {
        let serialQueue = DispatchQueue(label: "com.queue.Serial")
        for i in 1...5 {
            serialQueue.sync {
                if Thread.isMainThread{
                    print("task running in main thread")
                }else{
                    print("task running in background thread")
                }
                let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imgURL)
                print("\(i) completed downloading")
            }
        }
    }
    
    func doLongASyncTaskInConcurrentQueue() {
        let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
        for i in 1...5 {
            concurrentQueue.async {
                if Thread.isMainThread{
                    print("task running in main thread")
                }else{
                    print("task running in background thread")
                }
                let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imgURL)
                print("\(i) completed downloading")
            }
            print("\(i) executing")
        }
    }
    
    func doLongSyncTaskInConcurrentQueue() {
      let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
        for i in 1...5 {
            concurrentQueue.sync {
                if Thread.isMainThread{
                    print("task running in main thread")
                }else{
                    print("task running in background thread")
                }
                let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imgURL)
                print("\(i) completed downloading")
            }
            print("\(i) executed")
        }
    }
    
    func doMultipleSyncTaskWithinAsynchronousOperation() {
        let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
        concurrentQueue.async {
            let concurrentQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
            for i in 1...5 {
                concurrentQueue.sync {
                    let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                    let _ = try! Data(contentsOf: imgURL)
                    print("\(i) completed downloading")
                }
                print("\(i) executed")
            }
        }
    }
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    let cq = DispatchQueue(label: "concurrent.queue", attributes: .concurrent)
    let cq2 = DispatchQueue(label: "concurent.queue2", attributes: .concurrent)
    let sq = DispatchQueue(label: "serial.queue")
    
    func codeFragment() {
      print("code Fragment begin")
      print("Task Thread:\(Thread.current.description)")
      let imgURL = URL(string: "http://stackoverflow.com/questions/24058336/how-do-i-run-asynchronous-callbacks-in-playground")!
      let _ = try! Data(contentsOf: imgURL)
      print("code Fragment completed")
    }
    
    func serialQueueSync() { sq.sync { codeFragment() } }
    func serialQueueAsync() { sq.async { codeFragment() } }
    func concurrentQueueSync() { cq2.sync { codeFragment() } }
    func concurrentQueueAsync() { cq2.async { codeFragment() } }
    
    func tasksExecution() {
      (1...5).forEach { (_) in
        /// Using an concurrent queue to simulate concurent task executions.
        cq.async {
          print("Caller Thread:\(Thread.current.description)")
          /// Serial Queue Async, tasks run serially, because only one thread that can be used by serial queue, the underlying thread of serial queue.
          //serialQueueAsync()
          /// Serial Queue Sync, tasks run serially, because only one thread that can be used by serial queue,one by one of the callers' threads.
          //serialQueueSync()
          /// Concurrent Queue Async, tasks run concurrently, because tasks can run on different underlying threads
          //concurrentQueueAsync()
          /// Concurrent Queue Sync, tasks run concurrently, because tasks can run on different callers' thread
          //concurrentQueueSync()
        }
      }
    }
    tasksExecution()
    
    serialQueue.async {
        // this is one task
        // it can be any number of lines with any number of methods
    }
    serialQueue.async {
        // this is another task added to the same queue
        // this queue now has two tasks
    }
    
    let serialQueue = DispatchQueue(label: "serial")
    
    let concurrentQueue = DispatchQueue(label: "concurrent", attributes: [.concurrent])
    
    let concurrentQueue = DispatchQueue.global(qos: .default)
    
    DispatchQueue.global(qos: .default).sync {
        // task goes in here
    }
    
    DispatchQueue.global(qos: .default).async {
        // task goes in here
    }
    
    whichQueueShouldIUse.syncOrAsync {
        for i in 1...10 {
            print(i)
        }
        for i in 1...10 {
            print(i + 100)
        }
        for i in 1...10 {
            print(i + 1000)
        }
    }
    
    let serialQueue = DispatchQueue(label: "serial")
    let concurrentQueue = DispatchQueue.global(qos: .default)
    
    concurrentQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    concurrentQueue.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    
    1
    101
    2
    102
    103
    3
    104
    4
    105
    5
    
    serialQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    concurrentQueue.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    
    101
    1
    2
    102
    3
    103
    4
    104
    5
    105
    
    serialQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    serialQueue.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    
    1
    2
    3
    4
    5
    101
    102
    103
    104
    105
    
    serialQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    serialQueue2.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    
    1
    101
    2
    102
    3
    103
    4
    104
    5
    105
    
    serialQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    serialQueue.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    concurrentQueue.async {
        for i in 1...5 {
            print(i + 1000)
        }
    }
    
    1
    2
    3
    4
    5
    101
    102
    103
    104
    105
    1001
    1002
    1003
    1004
    1005
    
    1
    1001
    1002
    1003
    2
    1004
    1005
    3
    4
    5
    101
    102
    103
    104
    105
    
    concurrentQueue.sync {
        for i in 1...5 {
            print(i)
        }
    }
    concurrentQueue.async {
        for i in 1...5 {
            print(i + 100)
        }
    }
    
    1
    2
    3
    4
    5
    101
    102
    103
    104
    105
    
    DispatchQueue.main.sync { ... }
    
    DispatchQueue.main.sync { // stop the main queue and wait for the following to finish
        print("hello world") // this will never execute on the main queue because we just stopped it
    }
    // deadlock
    
    let serialQueue = DispatchQueue(label: "serialQueue", qos: .default, attributes: [], autoreleaseFrequency: .inherit, target: .global(qos: .default))
    
    let serialQueue = DispatchQueue(label: "SampleSerialQueue")
    //Block first
    serialQueue.async {
        for i in 1...10{
            print("Serial - First operation",i)
        }
    }
    
    //Block second
    serialQueue.async {
        for i in 1...10{
            print("Serial - Second operation",i)
        }
    }
    //Block Third
    serialQueue.async {
        for i in 1...10{
            print("Serial - Third operation",i)
        }
    }