天天看点

【iOS】GCD队列、同步异步

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

串行队列:

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

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

并发队列:

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

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

同步和异步

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

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

注意

1.同步执行没有开启新线程的能力, 所有的任务都只能在当前线程执行

2.异步执行有开启新线程的能力, 但是, 有开启新线程的能力, 也不一定会利用这种能力, 也就是说, 异步执行是否开启新线程, 需要具体问题具体分析

3.并发队列中的任务会放到不同的线程中去执行.

4.串行队列中的任务只会放到同一线程中去执行.

基本介绍算是完了,队列有2种,执行方式有2种,那么他们互相组合会是什么情况呢?

很显然,它们可以组合成4种情况:

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

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

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

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

验证:

1.串行队列同步执行

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

代码直接写在viewDidLoad里

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"

);

    NSLog(@"task4---%@",[NSThread currentThread]);

结果

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

26

:

00.511

GCD[

72214

:

3984485

] task1

2018

-

01

-

29

11

:

26

:

00.512

GCD[

72214

:

3984485

] task1---<nsthread: 

0x6080002610c0

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

26

:

00.512

GCD[

72214

:

3984485

] task2

2018

-

01

-

29

11

:

26

:

00.512

GCD[

72214

:

3984485

] task2---<nsthread: 

0x6080002610c0

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

26

:

00.512

GCD[

72214

:

3984485

] task3

2018

-

01

-

29

11

:

26

:

00.513

GCD[

72214

:

3984485

] task3---<nsthread: 

0x6080002610c0

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

26

:

00.513

GCD[

72214

:

3984485

] task4

2018

-

01

-

29

11

:

26

:

00.513

GCD[

72214

:

3984485

] task4---<nsthread: 

0x6080002610c0

>{number = 

1

, name = main}</nsthread: 

0x6080002610c0

></nsthread: 

0x6080002610c0

></nsthread: 

0x6080002610c0

></nsthread: 

0x6080002610c0

>

分析:任务是在当前线程(当前是主线程)顺序执行的。这也验证了

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

这里需要注意的是代码直接在viewDidLoad里写的,主队列也是一个串行队列,但在主线程中使用主队列同步执行会造成死锁,这里不讨论这个。另外,若在viewDidLoad新开一个子线程,去执行代码,结果是同样可以验证的:

1

[NSThread detachNewThreadSelector:@selector(threadAction) toTarget:self withObject:nil];

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

-(

void

)threadAction{

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"

);

NSLog(@

"task4---%@"

,[NSThread currentThread]);

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

27

:

31.056

GCD[

72230

:

3986823

] task1

2018

-

01

-

29

11

:

27

:

31.056

GCD[

72230

:

3986823

] task1---<nsthread: 

0x600000075f80

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

27

:

31.057

GCD[

72230

:

3986823

] task2

2018

-

01

-

29

11

:

27

:

31.057

GCD[

72230

:

3986823

] task2---<nsthread: 

0x600000075f80

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

27

:

31.058

GCD[

72230

:

3986823

] task3

2018

-

01

-

29

11

:

27

:

31.059

GCD[

72230

:

3986823

] task3---<nsthread: 

0x600000075f80

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

27

:

31.059

GCD[

72230

:

3986823

] task4

2018

-

01

-

29

11

:

27

:

31.059

GCD[

72230

:

3986823

] task4---<nsthread: 

0x600000075f80

>{number = 

3

, name = (

null

)}</nsthread: 

0x600000075f80

></nsthread: 

0x600000075f80

></nsthread: 

0x600000075f80

></nsthread: 

0x600000075f80

>

2.串行队列异步执行

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

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]);

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

30

:

19.254

GCD[

72269

:

3990336

] task1

2018

-

01

-

29

11

:

30

:

19.254

GCD[

72269

:

3990288

] task4

2018

-

01

-

29

11

:

30

:

19.254

GCD[

72269

:

3990288

] task4---<nsthread: 

0x60800006df00

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

30

:

19.254

GCD[

72269

:

3990336

] task1---<nsthread: 

0x60000007a9c0

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

30

:

19.255

GCD[

72269

:

3990336

] task2

2018

-

01

-

29

11

:

30

:

19.255

GCD[

72269

:

3990336

] task2---<nsthread: 

0x60000007a9c0

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

30

:

19.255

GCD[

72269

:

3990336

] task3

2018

-

01

-

29

11

:

30

:

19.255

GCD[

72269

:

3990336

] task3---<nsthread: 

0x60000007a9c0

>{number = 

3

, name = (

null

)}</nsthread: 

0x60000007a9c0

></nsthread: 

0x60000007a9c0

></nsthread: 

0x60000007a9c0

></nsthread: 

0x60800006df00

>

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

32

:

01.533

GCD[

72278

:

3992351

] task4

2018

-

01

-

29

11

:

32

:

01.533

GCD[

72278

:

3992391

] task1

2018

-

01

-

29

11

:

32

:

01.534

GCD[

72278

:

3992351

] task4---<nsthread: 

0x60800006d580

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

32

:

01.534

GCD[

72278

:

3992391

] task1---<nsthread: 

0x6080000771c0

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

32

:

01.534

GCD[

72278

:

3992391

] task2

2018

-

01

-

29

11

:

32

:

01.534

GCD[

72278

:

3992391

] task2---<nsthread: 

0x6080000771c0

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

32

:

01.534

GCD[

72278

:

3992391

] task3

2018

-

01

-

29

11

:

32

:

01.535

GCD[

72278

:

3992391

] task3---<nsthread: 

0x6080000771c0

>{number = 

3

, name = (

null

)}</nsthread: 

0x6080000771c0

></nsthread: 

0x6080000771c0

></nsthread: 

0x6080000771c0

></nsthread: 

0x60800006d580

>

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

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

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

3.并发队列同步执行

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

dispatch_queue_t queue = dispatch_queue_create(

"concurrentQueue"

, DISPATCH_QUEUE_CONCURRENT);

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"

);

NSLog(@

"task4---%@"

,[NSThread currentThread]);

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

40

:

40.274

GCD[

72316

:

3998532

] task1

2018

-

01

-

29

11

:

40

:

40.274

GCD[

72316

:

3998532

] task1---<nsthread: 

0x60800006ce80

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

40

:

40.274

GCD[

72316

:

3998532

] task2

2018

-

01

-

29

11

:

40

:

40.274

GCD[

72316

:

3998532

] task2---<nsthread: 

0x60800006ce80

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

40

:

40.274

GCD[

72316

:

3998532

] task3

2018

-

01

-

29

11

:

40

:

40.275

GCD[

72316

:

3998532

] task3---<nsthread: 

0x60800006ce80

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

40

:

40.275

GCD[

72316

:

3998532

] task4

2018

-

01

-

29

11

:

40

:

40.275

GCD[

72316

:

3998532

] task4---<nsthread: 

0x60800006ce80

>{number = 

1

, name = main}</nsthread: 

0x60800006ce80

></nsthread: 

0x60800006ce80

></nsthread: 

0x60800006ce80

></nsthread: 

0x60800006ce80

>

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

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

4.并发队列异步执行

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

dispatch_queue_t queue = dispatch_queue_create(

"concurrentQueue"

, DISPATCH_QUEUE_CONCURRENT);

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]);

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

47

:

23.235

GCD[

72367

:

4005184

] task2

2018

-

01

-

29

11

:

47

:

23.235

GCD[

72367

:

4005156

] task4

2018

-

01

-

29

11

:

47

:

23.235

GCD[

72367

:

4005183

] task1

2018

-

01

-

29

11

:

47

:

23.235

GCD[

72367

:

4005186

] task3

2018

-

01

-

29

11

:

47

:

23.236

GCD[

72367

:

4005156

] task4---<nsthread: 

0x600000262a80

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

47

:

23.236

GCD[

72367

:

4005184

] task2---<nsthread: 

0x608000267500

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

47

:

23.236

GCD[

72367

:

4005183

] task1---<nsthread: 

0x60000026f380

>{number = 

4

, name = (

null

)}

2018

-

01

-

29

11

:

47

:

23.236

GCD[

72367

:

4005186

] task3---<nsthread: 

0x608000267540

>{number = 

5

, name = (

null

)}</nsthread: 

0x608000267540

></nsthread: 

0x60000026f380

></nsthread: 

0x608000267500

></nsthread: 

0x600000262a80

>

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006982

] task1

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006934

] task4

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006984

] task3

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006981

] task2

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006934

] task4---<nsthread: 

0x608000068300

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

48

:

23.070

GCD[

72375

:

4006982

] task1---<nsthread: 

0x60000006db40

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

48

:

23.071

GCD[

72375

:

4006984

] task3---<nsthread: 

0x608000074300

>{number = 

4

, name = (

null

)}

2018

-

01

-

29

11

:

48

:

23.071

GCD[

72375

:

4006981

] task2---<nsthread: 

0x60000006d140

>{number = 

5

, name = (

null

)}</nsthread: 

0x60000006d140

></nsthread: 

0x608000074300

></nsthread: 

0x60000006db40

></nsthread: 

0x608000068300

>

1 2 3 4 5 6 7 8

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007604

] task4

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007680

] task2

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007683

] task1

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007681

] task3

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007604

] task4---<nsthread: 

0x6000000742c0

>{number = 

1

, name = main}

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007680

] task2---<nsthread: 

0x60800007d680

>{number = 

3

, name = (

null

)}

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007683

] task1---<nsthread: 

0x60000007f500

>{number = 

4

, name = (

null

)}

2018

-

01

-

29

11

:

48

:

42.930

GCD[

72380

:

4007681

] task3---<nsthread: 

0x60800007d5c0

>{number = 

5

, name = (

null

)}</nsthread: 

0x60800007d5c0

></nsthread: 

0x60000007f500

></nsthread: 

0x60800007d680

></nsthread: 

0x6000000742c0

>

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

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

最后总结一下:理解了串行并发和同步异步,我们的开发会变得更加高效,逻辑也会更加清晰,若你暂时没没弄懂,可以再回上去看看理论,跟着理论敲敲代码来加深理解