天天看點

【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,三個運作結果證明它們是在不同的線程中無序執行的,每個任務都開辟了新的線程去執行,并且執行順序是無序的,展現了并發的特性。是以我們經常也是使用這種方式做一些需求。驗證結果:

并發隊列異步執行:任務在開辟的多個子線程中執行(異步),并且是同時執行的(并發)

最後總結一下:了解了串行并發和同步異步,我們的開發會變得更加高效,邏輯也會更加清晰,若你暫時沒沒弄懂,可以再回上去看看理論,跟着理論敲敲代碼來加深了解