1. 程式人生 > >理解GCD中任務和佇列執行的原理

理解GCD中任務和佇列執行的原理

我們都知道IOS中常用於處理執行緒的三種方式:NSThreadNSOperationGCD,而GCD有很好的的優點就是不需要我們來處理runLoop的執行迴圈,它是一套基於C的併發程式設計(但是強調一下GCD並不能理解為多執行緒,因為這個並不是自己來控制執行緒),我們在使用的時候是不需要管理執行緒的任何生命週期,系統會自動幫我們管理。在底層是有一個任務佇列與執行緒池的概念,如果任務佇列與執行緒池的認識有點模糊,那可以先百度瞭解一下。我們先來理解以下幾個概念。

1、同步、非同步

同步:表示在當前執行緒(注意:不一定就表示主執行緒)執行任務,不去執行緒池中拿執行緒

非同步:表示不在當前執行緒執行任務,需要去執行緒池拿執行緒做處理

2、序列、併發

序列:表示所有任務一個接一個的線上程中執行

併發:表示所有任務可以同時在不同執行緒上執行

可能這樣粗略講解一下,還是不夠清晰,先我們這樣理解一下,同步,非同步是用來表示是否需要去執行緒池中取執行緒,而序列、併發是用來表示怎麼去任務佇列中取任務的。

下面我們組合一下上面兩種方式通過程式碼來依次講解。

viewDidLoad依次載入 [self test1]; [self test2]; [self test3]; [self test4];進行測試

1、同步、序列(在當前執行緒中一個一個的執行任務)

- (void)test1 {

    //建立一個序列佇列

    dispatch_queue_t queue = dispatch_queue_create("test1", DISPATCH_QUEUE_SERIAL);

    NSLog(@"thread start %@",[NSThread currentThread]);

    //同步執行任務

    for (NSInteger i = 0; i < 10; i++) {

        dispatch_sync(queue, ^{

            [NSThread sleepForTimeInterval:0.5];

            NSLog(

@"%zd -- %@", i,[NSThread currentThread]);

        });

    }

    [NSThread sleepForTimeInterval:1];

    NSLog(@"thread stop %@",[NSThread currentThread]);

}

執行結果:

2017-10-24 09:51:11.222 GCDTest[1510:249643] thread start {number = 1, name = main}

2017-10-24 09:51:11.723 GCDTest[1510:249643] 0 -- {number = 1, name = main}

2017-10-24 09:51:12.225 GCDTest[1510:249643] 1 -- {number = 1, name = main}

2017-10-24 09:51:12.725 GCDTest[1510:249643] 2 -- {number = 1, name = main}

2017-10-24 09:51:13.227 GCDTest[1510:249643] 3 -- {number = 1, name = main}

2017-10-24 09:51:13.728 GCDTest[1510:249643] 4 -- {number = 1, name = main}

2017-10-24 09:51:14.229 GCDTest[1510:249643] 5 -- {number = 1, name = main}

2017-10-24 09:51:14.730 GCDTest[1510:249643] 6 -- {number = 1, name = main}

2017-10-24 09:51:15.232 GCDTest[1510:249643] 7 -- {number = 1, name = main}

2017-10-24 09:51:15.733 GCDTest[1510:249643] 8 -- {number = 1, name = main}

2017-10-24 09:51:16.233 GCDTest[1510:249643] 9 -- {number = 1, name = main}

2017-10-24 09:51:17.234 GCDTest[1510:249643] thread stop {number = 1, name = main}

從結果可以看出,執行依次從上到下一個一個的執行。

2、非同步序列(會去執行緒池拿執行緒,但是任務順序執行)

- (void)test2 {

    //建立一個序列佇列

    dispatch_queue_t queue = dispatch_queue_create("test2", DISPATCH_QUEUE_SERIAL);

    NSLog(@"thread start %@",[NSThread currentThread]);

    //非同步執行任務

    for (NSInteger i = 0; i < 10; i++) {

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:0.5];

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

        });

    }

    [NSThread sleepForTimeInterval:1];

    NSLog(@"thread stop %@",[NSThread currentThread]);

}

執行結果:

2017-10-24 09:53:20.189 GCDTest[1557:268208] thread start {number = 1, name = main}

2017-10-24 09:53:20.691 GCDTest[1557:268552] 0 -- {number = 3, name = (null)}

2017-10-24 09:53:21.190 GCDTest[1557:268208] thread stop {number = 1, name = main}

2017-10-24 09:53:21.195 GCDTest[1557:268552] 1 -- {number = 3, name = (null)}

2017-10-24 09:53:21.698 GCDTest[1557:268552] 2 -- {number = 3, name = (null)}

2017-10-24 09:53:22.203 GCDTest[1557:268552] 3 -- {number = 3, name = (null)}

2017-10-24 09:53:22.709 GCDTest[1557:268552] 4 -- {number = 3, name = (null)}

2017-10-24 09:53:23.215 GCDTest[1557:268552] 5 -- {number = 3, name = (null)}

2017-10-24 09:53:23.721 GCDTest[1557:268552] 6 -- {number = 3, name = (null)}

2017-10-24 09:53:24.221 GCDTest[1557:268552] 7 -- {number = 3, name = (null)}

2017-10-24 09:53:24.722 GCDTest[1557:268552] 8 -- {number = 3, name = (null)}

2017-10-24 09:53:25.228 GCDTest[1557:268552] 9 -- {number = 3, name = (null)}

從執行結果看出,thread startthread stop在主執行緒中執行完成,其他的開闢了一個子執行緒執行

3、同步併發(在當前佇列執行,可以同時取出多個任務(取出那麼多工,只有一個執行緒,但是在實際中這種方式幾乎沒有什麼用)

- (void)test3 {

    //建立一個並行佇列

    dispatch_queue_t queue = dispatch_queue_create("test3", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"thread start %@",[NSThread currentThread]);

    //同步執行任務

    for (NSInteger i = 0; i < 10; i++) {

        dispatch_sync(queue, ^{

            [NSThread sleepForTimeInterval:0.5];

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

        });

    }

    [NSThread sleepForTimeInterval:1];

    NSLog(@"thread stop %@",[NSThread currentThread]);

}

執行結果:

2017-10-24 10:00:24.400 GCDTest[1619:296588] thread start {number = 1, name = main}

2017-10-24 10:00:24.901 GCDTest[1619:296588] 0 -- {number = 1, name = main}

2017-10-24 10:00:25.402 GCDTest[1619:296588] 1 -- {number = 1, name = main}

2017-10-24 10:00:25.904 GCDTest[1619:296588] 2 -- {number = 1, name = main}

2017-10-24 10:00:26.405 GCDTest[1619:296588] 3 -- {number = 1, name = main}

2017-10-24 10:00:26.907 GCDTest[1619:296588] 4 -- {number = 1, name = main}

2017-10-24 10:00:27.408 GCDTest[1619:296588] 5 -- {number = 1, name = main}

2017-10-24 10:00:27.910 GCDTest[1619:296588] 6 -- {number = 1, name = main}

2017-10-24 10:00:28.412 GCDTest[1619:296588] 7 -- {number = 1, name = main}

2017-10-24 10:00:28.913 GCDTest[1619:296588] 8 -- {number = 1, name = main}

2017-10-24 10:00:29.414 GCDTest[1619:296588] 9 -- {number = 1, name = main}

2017-10-24 10:00:30.416 GCDTest[1619:296588] thread stop {number = 1, name = main}

從執行結果可以看出,所有任務都在主執行緒中執行,任務依次一個一個執行。

4、併發、非同步(拿執行緒,同時拿任務)這才是多執行緒的精髓,靈魂

- (void)test4 {

    //建立一個並行佇列

    dispatch_queue_t queue = dispatch_queue_create("test4", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"thread start %@",[NSThread currentThread]);

    //非同步執行任務

    for (NSInteger i = 0; i < 10; i++) {

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:0.5];

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

        });

    }

    NSLog(@"thread stop %@",[NSThread currentThread]);

}

執行結果:

2017-10-24 10:07:44.857 GCDTest[1700:341404] thread start {number = 1, name = main}

2017-10-24 10:07:44.857 GCDTest[1700:341404] thread stop {number = 1, name = main}

2017-10-24 10:07:45.361 GCDTest[1700:341469] 1 -- {number = 3, name = (null)}

2017-10-24 10:07:45.361 GCDTest[1700:341468] 2 -- {number = 5, name = (null)}

2017-10-24 10:07:45.361 GCDTest[1700:341486] 0 -- {number = 4, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341489] 4 -- {number = 7, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341471] 3 -- {number = 6, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341490] 5 -- {number = 8, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341491] 6 -- {number = 9, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341494] 9 -- {number = 10, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341493] 8 -- {number = 12, name = (null)}

2017-10-24 10:07:45.362 GCDTest[1700:341492] 7 -- {number = 11, name = (null)}

從執行結果可以看出,thread startthread stop是在主執行緒中完成,其他的開了多個佇列再執行,至於具體的任務在哪條執行緒上執行,這就是GCD底層控制的,所以這也就說明了GCD不能叫做多執行緒,只能叫併發程式設計。