美文网首页
实践:GCD队列(串行、并发),同步异步执行

实践:GCD队列(串行、并发),同步异步执行

作者: A_Yun | 来源:发表于2023-09-06 12:14 被阅读0次

一、GCD的队列有两种,一种是串行队列,一种是并发队列。

1.串行队列:

任务按往队列里的添加先后顺序执行,先进先出(FIFO),前一个任务执行完再开始执行下一个任务。(我们开发中主线程队列就是一个串行队列,所以我们经常在主线程写的一般任务(不考虑多线程),都是顺序执行的)。

** 注意一个串行队列里只有一个线程 **。

2.并发队列:

任务会在这个队列中新开线程,并发同时执行(无序)。

我们GCD使用常伴有dispatch_syncdispatch_async,这就是同步执行和异步执行。

二、执行方式:同步和异步

1.同步执行:任务都在当前线程中执行,执行过程中会阻塞当前线程。

2.异步执行:任务会开辟新的线程,并在新的线程中执行,不会阻塞当前线程。

** 注意 **

1.同步执行没有开启新线程的能力, 所有的任务都只能在当前线程执行;
2.异步执行有开启新线程的能力, 但是, 有开启新线程的能力, 也不一定会利用这种能力, 也就是说, 异步执行是否开启新线程, 需要具体问题具体分析;
3.并发队列中的任务会放到不同的线程中去执行;
4.串行队列中的任务只会放到同一线程中去执行.

组合起来:

1).串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)

2).串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)

3).并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)

4).并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

三、代码实践:队列和执行方式组合

1.串行队列 - 同步执行

//1.串行队列-同步执行
dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
     
    dispatch_sync(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
     
    dispatch_sync(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
     
    NSLog(@"task4");

打印结果:
2023-09-07 11:40:58.147911+0800 虚拟定位[52431:1256240] task1
2023-09-07 11:40:58.148068+0800 虚拟定位[52431:1256240] task1---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.148179+0800 虚拟定位[52431:1256240] task2
2023-09-07 11:40:58.148323+0800 虚拟定位[52431:1256240] task2---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.148608+0800 虚拟定位[52431:1256240] task3
2023-09-07 11:40:58.149013+0800 虚拟定位[52431:1256240] task3---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.149264+0800 虚拟定位[52431:1256240] task4
2023-09-07 11:40:58.149473+0800 虚拟定位[52431:1256240] task4---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}

  
//若在viewDidLoad新开启一个子线程,结果是一样的
[NSThread detachNewThreadSelector:@selector(clickConsoleLog) toTarget:self withObject:nil];

分析:任务是在当前线程(当前是主线程)顺序执行的
验证结果:串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)
这里需要注意的是代码直接在viewDidLoad里写的,主队列也是一个串行队列,但在主线程中使用主队列同步执行会造成死锁

2.串行队列 - 异步执行

    dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
     
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);

打印结果:
2023-09-07 11:48:59.317367+0800 虚拟定位[52769:1263549] task4
2023-09-07 11:48:59.317378+0800 虚拟定位[52769:1263756] task1
2023-09-07 11:48:59.317487+0800 虚拟定位[52769:1263549] task4---<_NSMainThread: 0x6000021f4600>{number = 1, name = main}
2023-09-07 11:48:59.317556+0800 虚拟定位[52769:1263756] task1---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}
2023-09-07 11:48:59.317980+0800 虚拟定位[52769:1263756] task2
2023-09-07 11:48:59.318185+0800 虚拟定位[52769:1263756] task2---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}
2023-09-07 11:48:59.318415+0800 虚拟定位[52769:1263756] task3
2023-09-07 11:48:59.318676+0800 虚拟定位[52769:1263756] task3---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}

分析:主线程异步调用,我们先分析加到队列里的task任务1、2、3,确实都是在开辟了的新线程{number = 3, name = (null)}上顺序执行的,关于task4,由于是异步的,它也没加入队列queue,啥时候输出就看电脑心情
验证结果: 串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)

这里需要注意,由于新创建了串行线程,所以任务会在新开辟的线程上执行,若是直接在主队列异步调用,任务执行都在主线程上。

dispatch_queue_t queue_2 = dispatch_get_main_queue();
    dispatch_async(queue_2, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue_2, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue_2, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
     
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);

打印结果:
2023-09-07 11:56:12.817566+0800 虚拟定位[53133:1270516] task4
2023-09-07 11:56:12.817695+0800 虚拟定位[53133:1270516] task4---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818165+0800 虚拟定位[53133:1270516] task1
2023-09-07 11:56:12.818308+0800 虚拟定位[53133:1270516] task1---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818430+0800 虚拟定位[53133:1270516] task2
2023-09-07 11:56:12.818556+0800 虚拟定位[53133:1270516] task2---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818672+0800 虚拟定位[53133:1270516] task3
2023-09-07 11:56:12.824585+0800 虚拟定位[53133:1270516] task3---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}

3.并发队列 - 同步执行

    dispatch_queue_t queue_3 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue_3, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
     
    dispatch_sync(queue_3, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
     
    dispatch_sync(queue_3, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
     
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);

打印结果:
2023-09-07 12:02:38.767374+0800 虚拟定位[53480:1277012] task1
2023-09-07 12:02:38.767506+0800 虚拟定位[53480:1277012] task1---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.767600+0800 虚拟定位[53480:1277012] task2
2023-09-07 12:02:38.767719+0800 虚拟定位[53480:1277012] task2---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.767861+0800 虚拟定位[53480:1277012] task3
2023-09-07 12:02:38.768231+0800 虚拟定位[53480:1277012] task3---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.768362+0800 虚拟定位[53480:1277012] task4
2023-09-07 12:02:38.768675+0800 虚拟定位[53480:1277012] task4---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}

分析:任务是在当前线程(是主线程没有开辟新线程)顺序执行的,跟串行同步一样,虽是并发队列,却不能并发
验证结果: 并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)

4.并发队列 - 异步执行

    dispatch_queue_t queue_3 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue_3, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue_3, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
     
    dispatch_async(queue_3, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
     
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);


打印结果:
2023-09-07 12:06:54.146885+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:06:54.146899+0800 虚拟定位[53698:1280781] task1
2023-09-07 12:06:54.146919+0800 虚拟定位[53698:1280779] task2
2023-09-07 12:06:54.146929+0800 虚拟定位[53698:1280780] task3
2023-09-07 12:06:54.147027+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:06:54.147149+0800 虚拟定位[53698:1280781] task1---<NSThread: 0x600002f4c700>{number = 7, name = (null)}
2023-09-07 12:06:54.147892+0800 虚拟定位[53698:1280779] task2---<NSThread: 0x600002f7c680>{number = 6, name = (null)}
2023-09-07 12:06:54.148040+0800 虚拟定位[53698:1280780] task3---<NSThread: 0x600002f7c240>{number = 5, name = (null)}

2023-09-07 12:09:07.365986+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:09:07.366002+0800 虚拟定位[53698:1280786] task1
2023-09-07 12:09:07.366061+0800 虚拟定位[53698:1280787] task2
2023-09-07 12:09:07.366130+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:09:07.366092+0800 虚拟定位[53698:1282794] task3
2023-09-07 12:09:07.366221+0800 虚拟定位[53698:1280786] task1---<NSThread: 0x600002f0ae00>{number = 8, name = (null)}
2023-09-07 12:09:07.366957+0800 虚拟定位[53698:1280787] task2---<NSThread: 0x600002f6d6c0>{number = 9, name = (null)}
2023-09-07 12:09:07.367243+0800 虚拟定位[53698:1282794] task3---<NSThread: 0x600002f6dc40>{number = 10, name = (null)}

2023-09-07 12:09:28.781997+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:09:28.782034+0800 虚拟定位[53698:1282794] task1
2023-09-07 12:09:28.782060+0800 虚拟定位[53698:1283078] task2
2023-09-07 12:09:28.782120+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:09:28.782103+0800 虚拟定位[53698:1282796] task3
2023-09-07 12:09:28.782221+0800 虚拟定位[53698:1282794] task1---<NSThread: 0x600002f6dc40>{number = 10, name = (null)}
2023-09-07 12:09:28.782778+0800 虚拟定位[53698:1283078] task2---<NSThread: 0x600002f0a940>{number = 12, name = (null)}
2023-09-07 12:09:28.783021+0800 虚拟定位[53698:1282796] task3---<NSThread: 0x600002f0b7c0>{number = 11, name = (null)}

分析:先看task4吧,没有加入队列,所以肯定是在主线程执行的,由于异步,啥时候执行还是要看电脑心情...好了,言归正传,我们看加入到并发队列里的任务1、2、3,三个运行结果证明它们是在不同的线程中无序执行的,每个任务都开辟了新的线程去执行,并且执行顺序是无序的,体现了并发的特性。所以我们经常也是使用这种方式做一些需求
验证结果: 并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

参考:https://www.ngui.cc/el/3221614.html?action=onClick

相关文章

  • iOS - 多线程(二) GCD讲解

    目录: 1.GCD简介2.串行队列 + 同步执行3.串行队列 + 异步执行4.并发队列 + 同步执行5.并发队列 ...

  • GCD学习总结

    GCD容易混淆的概念 任务,同步,异步 ,串行队列,并发队列 任务就是要做的事情 同步和异步是用来执行任务的 串行...

  • 队列dispatch_queue的使用

    队列分为:串行队列、并发队列和主队列,主队列也叫特殊串行队列,是GCD自带的。 任务的执行分为:同步执行和异步执行...

  • 关于GCD总结

    什么是GCD 理解串行、并发及同步异步 串行和并发 同步和异步 队列 串行队列 两者等效.2)使用主队列(在主队列...

  • 关于多线程GCD 串行/并行、同步/异步

    一、GCD串行/并行队列创建 串行队列: 并行队列: 二、GCD串行/并行队列同步/异步执行 执行内容1: 执行结...

  • iOS GCD笔记

    串行队列 并发队列 主队列 全局并发队列 同步执行 异步执行 同步+并发队列 = 没有开启新线程,串行执行任务 s...

  • 多线程

    iOS中的几种多线程GCD1、GCD分为任务和队列,任务(同步,异步)队列(串行,并发),同步串行,同步主队列的情...

  • GCD与NSOperation之间的区别

    GCD: 将任务(block)添加到队列(串行/并发/主队列),并且指定任务执行的函数(同步/异步)GCD是底层的...

  • iOS GCD底层分析(3)--栅栏函数、信号量、调度组、事件源

    前言 上片文章分析了GCD队列和函数的使用方式、串行队列和并发队列的创建、同步函数和异步函数底层执行流程、串行队列...

  • 2021--- GCD

    gcd同步,异步,串行队列,并发队列,全局队列,主队列,以及死锁。 1、gcd队列阻塞问题[https://www...

网友评论

      本文标题:实践:GCD队列(串行、并发),同步异步执行

      本文链接:https://www.haomeiwen.com/subject/ybukvdtx.html