并发编程 - GCD的任务和队列

2024-08-29 10:36
文章标签 并发 编程 队列 任务 gcd

本文主要是介绍并发编程 - GCD的任务和队列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

在并发编程的世界中,我们可以从开发中最常用的 Grand Central Dispatch (GCD) 开始着手。相比于其他多线程方案,GCD 具备诸多优势:

  • 支持多核并行计算
  • 自动利用多核 CPU 的资源
  • 自动管理线程的生命周期
  • 提供两个可直接使用的队列(主队列和全局队列)
  • 允许我们创建自定义队列

在 GCD 中,最核心的两个概念便是任务队列

任务

任务就是执行操作的意思也就是我们在线程中执行的那一段代码,在GCD中就是放在block里面的代码。

而执行任务有两种方式:

同步执行(sync):

  1. 同步添加任务到指定的队列中,任务会顺序执行,在上一个任务结束之前,当前任务会一直等待,直到队列里面的任务完成后再继续执行。
  2. 只能在当前的线程中执行任务,不具备开启新线程的能力。

异步执行(async):

  1. 异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
  2. 可以在新的现场中执行任务,具备开启新线程的能力。

这两者的主要区别在于:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。

简单来讲,同步同时只能做一件事儿,而异步可以同时做多件事儿。

但是有一个非常需要注意的一点:异步执行(async)虽然具备开启新线程的能力,但是并不一定就会开启新的线程,这还和任务指定的队列类型有关。

队列

队列指的是执行任务的队列,队列是一种特殊的线性表,采用FIFO(先进先出)的原则,新的任务总是被插入到队列的末尾。而任务在执行时总是从队列的最头部开始读取执行。

队列的概念大家应该并不陌生,队列先进先出,栈先进后出,在这里就不过多介绍了。

在GCD中队列也是有两种:

串行队列(Serial Dispatch Queue):

  • 在串行队列中每次只能有一个任务被执行,队列中的所有任务都需要按顺序执行,在串行队列中可能会开启新的线程。

并发队列(Concurrent Dispatch Queue):

  • 在并发队列中任务可以同时执行,可以开启多个线程同时执行任务。

两者的主要区别在于队列中的任务执行顺序不同。

同样值得注意的是并发队列的并发功能只有在执行异步任务时才有效。

关于队列和任务的组合我们先给出两个图片直观的感受一下,然后我们再来详细的讨论一下它们的使用场景。

使用任务和队列

GCD之所以在并发编程中比较受欢迎的原因就是使用起来很容易,只需要两个步骤:

  1. 创建队列
  2. 将任务添加到队列

创建队列

使用DispatchQueue提供的初始化方法直接创建串行队列和并发队列。

        //1.创建一个串行队列let queue = DispatchQueue(label: "com.louis.GCDTestManager")//2.创建一个并发队列let queue1 = DispatchQueue(label: "com.louis.GCDTestManager1", qos: .default, attributes: .concurrent)

另外GCD还提供了两个特殊的队列:主队列(Main Queue)和全局队列(Global Queue)。

        //3.主队列let mainQueue = DispatchQueue.main//4.全局队列let globalQueue = DispatchQueue.global()

主队列属于串行队列,与主线程关联。全局队列属于并发队列,由系统提供。

创建任务

有了队列之后我们就可以在指定的队列中执行任务。

        //1.同步执行任务queue.sync {for i in 0...10 {print("同步执行任务1:\(i)")}}//2.异步执行任务queue.async {for i in 0...10 {print("异步执行任务1:\(i)")}}

在上面的代码中我们都采用了串行队列来进行同步和异步执行任务。

队列和任务组合

不管是队列还是任务的创建都非常容易,但是当我们使用它们时并没有这么简单,我们需要根据场景来判断队列和任务该如何组合,那我们就需要知道每一个组合的结果。

我们先来讨论比较简单的串行队列。

串行队列+同步任务

任务将会在当前线程中执行,不会开启新的线程。任务会按顺序一个一个执行。

代码如下:

    /// 同步任务 + 串行队列func syncSerial() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("syncSerial 开始")//1.创建一个串行队列let queue = DispatchQueue(label: "com.louis.GCDTestManager")//2.同步执行任务1queue.sync {for i in 0...10 {print("同步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.同步执行任务2queue.sync {for i in 0...10 {print("同步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("syncSerial 结束")}

结果如下:

当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

syncSerial 开始

同步任务1:0---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:1---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:2---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:3---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:4---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:5---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:6---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:7---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:8---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:9---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务1:10---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:0---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:1---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:2---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:3---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:4---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:5---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:6---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:7---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:8---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:9---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

同步任务2:10---当前线程:<_NSMainThread: 0x301cac000>{number = 1, name = main}

syncSerial 结束

  1. 可以发现所有的任务当前线程中执行,没有开启新的线程。
  2. 所有任务都在“syncSerial 开始”和“syncSerial 结束”之间。
  3. 所有任务都是按顺序执行的。
串行队列+异步任务

可能会开启新的线程,但由于是串行队列任务仍然会按顺序执行,一个任务执行完再执行另一个任务。

代码如下:

    /// 异步任务 + 串行队列func asyncSerial() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("asyncSerial 开始")//1.创建一个串行队列let queue = DispatchQueue(label: "com.louis.GCDTestManager")//2.异步执行任务1queue.async {for i in 0...10 {print("异步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.异步执行任务2queue.async {for i in 0...10 {print("异步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("asyncSerial 结束")}

结果如下:

当前线程:<_NSMainThread: 0x3000bc040>{number = 1, name = main}

asyncSerial 开始

asyncSerial 结束

异步任务1:0---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:1---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:2---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:3---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:4---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:5---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:6---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:7---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:8---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:9---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务1:10---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:0---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:1---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:2---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:3---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:4---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:5---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:6---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:7---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:8---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:9---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

异步任务2:10---当前线程:<NSThread: 0x3000e8340>{number = 3, name = (null)}

  1. 开启了新的线程。
  2. 所有任务仍然是顺序执行的。
  3. 所有任务都是在asyncSerial 结束之后执行的,说明异步不会阻塞当前线程。
并发队列+同步任务

任务在当前线程中执行,不会开启新的线程,任务按顺序执行。

代码如下:

    /// 同步任务 + 并发队列func syncConcurrent() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("syncConcurrent 开始")//1.创建一个并发队列let queue = DispatchQueue(label: "com.louis.GCDTestManager", attributes: .concurrent)//2.同步执行任务1queue.sync {for i in 0...10 {print("同步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.同步执行任务2queue.sync {for i in 0...10 {print("同步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("syncConcurrent 结束")}

结果如下:

当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

syncConcurrent 开始

同步任务1:0---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:1---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:2---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:3---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:4---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:5---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:6---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:7---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:8---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:9---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务1:10---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:0---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:1---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:2---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:3---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:4---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:5---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:6---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:7---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:8---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:9---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

同步任务2:10---当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

syncConcurrent 结束

  1. 所有任务都在当前线程执行。
  2. 所有任务都在“syncConcurrent 开始”和“syncConcurrent 结束”之间执行。
  3. 任务顺序执行,因为都是同步任务,所以即使在并发队列中它也不具备开启新线程的能力。
并发队列+异步任务

可以开启多个线程,任务同时执行,没有固定顺序。

代码如下:

   /// 异步任务 + 并发队列func asyncConcurrent() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("asyncConcurrent 开始")//1.创建一个并发队列let queue = DispatchQueue(label: "com.louis.GCDTestManager", attributes: .concurrent)//2.异步执行任务1queue.async {for i in 0...10 {print("异步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.异步执行任务2queue.async {for i in 0...10 {print("异步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("asyncConcurrent 结束")}

结果如下:

当前线程:<_NSMainThread: 0x3009f8100>{number = 1, name = main}

asyncConcurrent 开始

asyncConcurrent 结束

异步任务1:0---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:1---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:2---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:3---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:4---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务2:0---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:1---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:2---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务1:5---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:6---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务1:7---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务2:3---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务1:8---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务2:4---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务1:9---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务2:5---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务1:10---当前线程:<NSThread: 0x3009ac200>{number = 9, name = (null)}

异步任务2:6---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:7---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:8---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:9---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

异步任务2:10---当前线程:<NSThread: 0x3009a8000>{number = 10, name = (null)}

  1. 开了多个线程。
  2. 任务执行没有固定顺序。
  3. 所有任务都在“asyncConcurrent 结束”之后执行,说明没有阻塞线程。

主队列

分析完了所有任务和队列的组合和结构,我们还需要格外注意一下主队列,主队列属于串行队列,但由于我们的代码默认在主队列上执行所以在进行组合时会有些不一样的效果。

主队列+同步任务

在主队列中同步执行任务会直接卡死崩溃。

代码如下:

    /// 同步任务 + 主队列func syncMain() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("syncMain 开始")//1.获取主队列let queue = DispatchQueue.main//2.同步执行任务1queue.sync {for i in 0...10 {print("同步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.同步执行任务2queue.sync {for i in 0...10 {print("同步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("syncMain 结束")}

结果直接崩溃:

因为当我们把同步任务1添加到主队列时,它会等待当前队列中的任务执行完成再来执行任务1。

但是由于我们把任务1添加到了主队列,主队列又需要等待任务1执行完成才能继续执行。

这样就造成了相互等待,所以就卡死了。

但是如果我们并不是在主线程调用这个方法,那么就不会出现问题。

修改代码如下:

    /// 同步任务 + 主队列func syncMain() {let thread = Thread(target: self, selector: #selector(startSyncMain), object: nil)thread.start()}@objc func startSyncMain() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("syncMain 开始")//1.获取主队列let queue = DispatchQueue.main//2.同步执行任务1queue.sync {for i in 0...10 {print("同步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.同步执行任务2queue.sync {for i in 0...10 {print("同步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("syncMain 结束")}

结果如下:

当前线程:<NSThread: 0x301d200c0>{number = 7, name = (null)}

syncMain 开始

同步任务1:0---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:1---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:2---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:3---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:4---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:5---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:6---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:7---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:8---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:9---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务1:10---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:0---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:1---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:2---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:3---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:4---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:5---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:6---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:7---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:8---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:9---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

同步任务2:10---当前线程:<_NSMainThread: 0x301d6c100>{number = 1, name = main}

syncMain 结束

  1. 所有任务都在主线程中执行。
  2. 所有任务顺序执行。
  3. 所有任务都在“syncMain 开始”和“syncMain 结束”之间执行。

主队列+异步任务

不会开启新的线程,任务顺序执行。

代码如下:

    /// 异步任务 + 主队列func asyncMain() {// 当前线程print("当前线程:\(Thread.current)")// 开始print("asyncMain 开始")//1.获取主队列let queue = DispatchQueue.main//2.异步执行任务1queue.async {for i in 0...10 {print("异步任务1:\(i)" + "---当前线程:\(Thread.current)")}}//3.异步执行任务2queue.async {for i in 0...10 {print("异步任务2:\(i)" + "---当前线程:\(Thread.current)")}}print("asyncMain 结束")}

结果如下:

当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

asyncMain 开始

asyncMain 结束

异步任务1:0---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:1---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:2---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:3---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:4---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:5---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:6---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:7---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:8---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:9---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务1:10---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:0---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:1---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:2---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:3---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:4---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:5---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:6---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:7---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:8---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:9---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

异步任务2:10---当前线程:<_NSMainThread: 0x3028c4100>{number = 1, name = main}

  1. 所有任务都在主线程中执行,没有开启新的线程。
  2. 任务都是在“asyncMain 结束”之后执行,没有阻塞当前线程。
  3. 任务按顺序执行,因为主队列时串行队列。

结语

本篇博客篇幅较长,但这只是 GCD 的入门介绍。事实上,我们讨论的内容还算基础,仅涉及了队列和任务的创建,以及它们如何组合在一起工作。然而,掌握这些基础概念是深入理解 GCD 并有效应用其强大功能的第一步。

未来还有更多复杂的机制和高级用法等待我们探索。希望通过这篇文章,你对 GCD 有了初步的认识,以后的博客我们会继续探讨GCD以及其它并发编程相关的内容。

这篇关于并发编程 - GCD的任务和队列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117617

相关文章

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

C++ RabbitMq消息队列组件详解

《C++RabbitMq消息队列组件详解》:本文主要介绍C++RabbitMq消息队列组件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. RabbitMq介绍2. 安装RabbitMQ3. 安装 RabbitMQ 的 C++客户端库4. A

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

golang实现延迟队列(delay queue)的两种实现

《golang实现延迟队列(delayqueue)的两种实现》本文主要介绍了golang实现延迟队列(delayqueue)的两种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录1 延迟队列:邮件提醒、订单自动取消2 实现2.1 simplChina编程e简单版:go自带的time

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与