iOS開發(fā)之多線程筆記(四)之GCD

Grand Central Dispatch

純C語言月培,提供了非常多強大的函數(shù)

線程相關知識以及GCD概念介紹不是本篇重點這里不做過多涉及

(一)OC篇

只想看swift的可以直接跳過,看下面的swift篇

隊列的創(chuàng)建
  • dispatch_queue_create(param1,param2)
     /**
     創(chuàng)建一個隊列

     @param "identifier" 隊列的唯一標識
     @param DISPATCH_QUEUE_SERIAL 串行隊列還是并行隊列
     @return 返回實例對象(姑且認為它是個對象)
     */
    dispatch_queue_t queue = dispatch_queue_create("identifier", DISPATCH_QUEUE_SERIAL);
  • param1需要傳入一個c語言類型字符串,作用是用來標記當前queue,可以傳空.可以通過dispatch_queue_get_label來獲取queue的標記.
const *char s = dispatch_queue_get_label(queue);
主隊列 dispatch_get_main_queue
dispatch_queue_t mainQueue = dispatch_get_main_queue();
全局隊列 dispatch_get_global_queue(param1, param2)

會獲取一個全局隊列门岔,我們姑且理解為系統(tǒng)為我們開啟的一些全局線程烹棉。我們用priority指定隊列的優(yōu)先級豌拙,而flag作為保留字段備用(一般為0)。

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
  • param1 傳入隊列優(yōu)先級.
  • param2 保留字段,目前沒什么用,直接傳0.
隊列中任務的執(zhí)行:
  1. 串行(Serial):讓任務一個接著一個地執(zhí)行(一個任務執(zhí)行完畢后镶苞,再執(zhí)行下一個任務)
  2. 并發(fā)(Concurrent):可以讓多個任務并發(fā)(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務)并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效肝断。
  3. 同步(Synchronous):在當前線程中執(zhí)行任務,不具備開啟新線程的能力
  4. 異步(Asynchronous):在新的線程中執(zhí)行任務丈钙,具備開啟新線程的能力
  • 串行隊列,同步執(zhí)行
- (void)sync_serial {
    NSLog(@"mian_start");
    dispatch_queue_t queue = dispatch_queue_create("com.test.id", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        [self taskBegin];
    });
    dispatch_sync(queue, ^{
         [self taskBegin];
    });
    dispatch_sync(queue, ^{
         [self taskBegin];
    });
    NSLog(@"mian_end");
}

- (void)taskBegin {
    NSThread *thread = [NSThread currentThread];
    NSLog(@"tread_begin ,%@",thread);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"tread_end ,%@",thread);
}

控制臺日志如下:

2018-01-23 15:53:08.274847+0800 Thread[74746:3368362] mian_start
2018-01-23 15:53:08.275235+0800 Thread[74746:3368362] tread_begin ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:11.276825+0800 Thread[74746:3368362] tread_end ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:11.277165+0800 Thread[74746:3368362] tread_begin ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:14.277633+0800 Thread[74746:3368362] tread_end ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:14.277845+0800 Thread[74746:3368362] tread_begin ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:17.278809+0800 Thread[74746:3368362] tread_end ,<NSThread: 0x604000064e40>{number = 1, name = main}
2018-01-23 15:53:17.279073+0800 Thread[74746:3368362] mian_end

總結:不重新開辟線程,線程中的任務按順序執(zhí)行.

  • 并行隊列,同步執(zhí)行
- (void)sync_Concurrent {
    NSLog(@"mian_start");
    dispatch_queue_t queue = dispatch_queue_create("222", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        [self taskBegin];
    });
    dispatch_sync(queue, ^{
        [self taskBegin];
    });
    dispatch_sync(queue, ^{
        [self taskBegin];
    });
    NSLog(@"mian_end");
}

- (void)taskBegin {
    NSThread *thread = [NSThread currentThread];
    NSLog(@"tread_begin ,%@",thread);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"tread_end ,%@",thread);
}

打印日志如下:

2018-01-29 11:53:22.464506+0800 Thread[60281:937006] mian_start
2018-01-29 11:53:22.464832+0800 Thread[60281:937006] tread_begin ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:25.465294+0800 Thread[60281:937006] tread_end ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:25.465514+0800 Thread[60281:937006] tread_begin ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:28.466237+0800 Thread[60281:937006] tread_end ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:28.466548+0800 Thread[60281:937006] tread_begin ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:31.467731+0800 Thread[60281:937006] tread_end ,<NSThread: 0x600000073bc0>{number = 1, name = main}
2018-01-29 11:53:31.467904+0800 Thread[60281:937006] mian_end

總結:不開辟新線程,任務按順序執(zhí)行.

  • 串行隊列,異步執(zhí)行
- (void)async_serial {
    NSLog(@"mian_start");
    dispatch_queue_t queue = dispatch_queue_create("333", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    NSLog(@"mian_end");
}

- (void)taskBegin {
    NSThread *thread = [NSThread currentThread];
    NSLog(@"tread_begin ,%@",thread);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"tread_end ,%@",thread);
}

日志如下:

2018-01-29 11:56:52.776368+0800 Thread[60281:937006] mian_start
2018-01-29 11:56:52.776701+0800 Thread[60281:937006] mian_end
2018-01-29 11:56:52.776777+0800 Thread[60281:951989] tread_begin ,<NSThread: 0x600000274780>{number = 5, name = (null)}
2018-01-29 11:56:55.779400+0800 Thread[60281:951989] tread_end ,<NSThread: 0x600000274780>{number = 5, name = (null)}
2018-01-29 11:56:55.779647+0800 Thread[60281:951989] tread_begin ,<NSThread: 0x600000274780>{number = 5, name = (null)}
2018-01-29 11:56:58.784670+0800 Thread[60281:951989] tread_end ,<NSThread: 0x600000274780>{number = 5, name = (null)}
2018-01-29 11:56:58.784963+0800 Thread[60281:951989] tread_begin ,<NSThread: 0x600000274780>{number = 5, name = (null)}
2018-01-29 11:57:01.786699+0800 Thread[60281:951989] tread_end ,<NSThread: 0x600000274780>{number = 5, name = (null)}

總結:只會另外開辟一個線程,線程中的任務按順序執(zhí)行.而且新開辟的線程不會阻塞當前線程.兩個線程中的代碼同時執(zhí)行.

  • 并行隊列,異步執(zhí)行
- (void)async_concurrent {
    NSLog(@"mian_start");
    dispatch_queue_t queue = dispatch_queue_create("333", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    dispatch_async(queue, ^{
        [self taskBegin];
    });
    NSLog(@"mian_end");
}

- (void)taskBegin {
    NSThread *thread = [NSThread currentThread];
    NSLog(@"tread_begin ,%@",thread);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"tread_end ,%@",thread);
}

日志如下:

2018-01-29 13:07:10.507523+0800 Thread[60281:937006] mian_start
2018-01-29 13:07:10.507810+0800 Thread[60281:937006] mian_end
2018-01-29 13:07:10.507901+0800 Thread[60281:1109308] tread_begin ,<NSThread: 0x6040004654c0>{number = 7, name = (null)}
2018-01-29 13:07:10.507903+0800 Thread[60281:951997] tread_begin ,<NSThread: 0x600000476d80>{number = 8, name = (null)}
2018-01-29 13:07:10.507926+0800 Thread[60281:1109326] tread_begin ,<NSThread: 0x60400046c740>{number = 9, name = (null)}
2018-01-29 13:07:13.512128+0800 Thread[60281:1109308] tread_end ,<NSThread: 0x6040004654c0>{number = 7, name = (null)}
2018-01-29 13:07:13.512173+0800 Thread[60281:951997] tread_end ,<NSThread: 0x600000476d80>{number = 8, name = (null)}
2018-01-29 13:07:13.512221+0800 Thread[60281:1109326] tread_end ,<NSThread: 0x60400046c740>{number = 9, name = (null)}

總結:會開啟多個線程,.新開辟的線程不會相互阻塞.多個線程中的任務同時執(zhí)行.

調度組 dispatch_group_t

項目中,我們有時候可能會遇到這樣的場景.需要開啟多個線程并發(fā)執(zhí)行任務,最后需要在所有任務執(zhí)行完成后再做操作.這里我們就可以使用GCD中的調度組來實現(xiàn):

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    NSLog(@"調度組開始執(zhí)行!!!");
    dispatch_group_async(group, queue, ^{
        for(int i = 0; i < 5; i++) {
            NSLog(@"thread1 -> %d", i);
        }
    });
    dispatch_group_async(group, queue, ^{
        for(int i = 0; i < 5; i++) {
            NSLog(@"thread2 -> %d", i);
        }
    });
    
    dispatch_group_async(group, queue, ^{
        for(int i = 0; i < 5; i++) {
            NSLog(@"thread3 -> %d", i);
        }
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"所有循環(huán)執(zhí)行完畢!!!");
    });

打印日志如下:

2018-02-01 17:33:33.687543+0800 Thread[63088:367476] 調度組開始執(zhí)行!!!
2018-02-01 17:33:33.687879+0800 Thread[63088:367562] thread1 -> 0
2018-02-01 17:33:33.687882+0800 Thread[63088:367553] thread2 -> 0
2018-02-01 17:33:33.687888+0800 Thread[63088:367558] thread3 -> 0
2018-02-01 17:33:33.688551+0800 Thread[63088:367562] thread1 -> 1
2018-02-01 17:33:33.688569+0800 Thread[63088:367553] thread2 -> 1
2018-02-01 17:33:33.688671+0800 Thread[63088:367558] thread3 -> 1
2018-02-01 17:33:33.688963+0800 Thread[63088:367553] thread2 -> 2
2018-02-01 17:33:33.688982+0800 Thread[63088:367562] thread1 -> 2
2018-02-01 17:33:33.689465+0800 Thread[63088:367558] thread3 -> 2
2018-02-01 17:33:33.689706+0800 Thread[63088:367553] thread2 -> 3
2018-02-01 17:33:33.690041+0800 Thread[63088:367562] thread1 -> 3
2018-02-01 17:33:33.690279+0800 Thread[63088:367558] thread3 -> 3
2018-02-01 17:33:33.691043+0800 Thread[63088:367553] thread2 -> 4
2018-02-01 17:33:33.691211+0800 Thread[63088:367562] thread1 -> 4
2018-02-01 17:33:33.691389+0800 Thread[63088:367558] thread3 -> 4
2018-02-01 17:33:33.691583+0800 Thread[63088:367553] thread2 -> 5
2018-02-01 17:33:33.691826+0800 Thread[63088:367562] thread1 -> 5
2018-02-01 17:33:33.692019+0800 Thread[63088:367558] thread3 -> 5
2018-02-01 17:33:33.692796+0800 Thread[63088:367558] 所有循環(huán)執(zhí)行完畢!!!

總結:所有任務執(zhí)行完成后的操作在 dispatch_group_notify 中寫代碼即可.

  • 但是這里有一個問題:隊列中的任務代碼是一段for循環(huán),for循環(huán)是同步執(zhí)行的.如果代碼塊中的任務是異步執(zhí)行的,還會是現(xiàn)在的效果嗎?
  • 比如: 我要發(fā)起3個異步的網(wǎng)絡請求,需要等到3個請求都有響應后再做下一步操作.此時我們仍然使用上面的代碼是否能實現(xiàn)呢?
  • 這里我用延時操作來模擬異步網(wǎng)絡請求延時效果.
- (void)group_asynBlock {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    NSLog(@"group 開始執(zhí)行 !!!");
    dispatch_group_async(group, queue, ^{
        NSLog(@"block1 begin !!!");
        [self request:1];
        NSLog(@"block1 end !!!");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"block2 begin !!!");
        [self request:2];
        NSLog(@"block2 end !!!");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"block3 begin !!!");
        [self request:3];
        NSLog(@"block3 end !!!");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"group 結束 !!!");
    });
}

- (void)request:(NSInteger)count {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"請求%ld 開始 !!!", count);
        [NSThread sleepForTimeInterval:3];
         NSLog(@"請求%ld 結束 !!!", count);
    });
}

下面我可們可以來猜測一下日志會是怎樣的.
我們所期望的是這樣的

group 開始執(zhí)行 !!!
block1 begin !!!
block2 begin !!!
block3 begin !!!
block1 end !!!
block2 end !!!
block3 end !!!
請求2 開始 !!!
請求1 開始 !!!
請求3 開始 !!!
請求2 結束 !!!
請求1 結束 !!!
請求3 結束 !!!
group 結束 !!!

但是實際日志是這樣的:

2018-02-01 17:55:42.008339+0800 Thread[67540:402087] group 開始執(zhí)行 !!!
2018-02-01 17:55:42.008609+0800 Thread[67540:402136] block1 begin !!!
2018-02-01 17:55:42.008619+0800 Thread[67540:402132] block2 begin !!!
2018-02-01 17:55:42.008631+0800 Thread[67540:402133] block3 begin !!!
2018-02-01 17:55:42.009244+0800 Thread[67540:402136] block1 end !!!
2018-02-01 17:55:42.009277+0800 Thread[67540:402132] block2 end !!!
2018-02-01 17:55:42.009280+0800 Thread[67540:402134] 請求1 開始 !!!
2018-02-01 17:55:42.009309+0800 Thread[67540:402135] 請求2 開始 !!!
2018-02-01 17:55:42.009444+0800 Thread[67540:402133] block3 end !!!
2018-02-01 17:55:42.009456+0800 Thread[67540:402136] 請求3 開始 !!!
2018-02-01 17:55:42.010551+0800 Thread[67540:402133] group 結束 !!!
2018-02-01 17:55:45.013680+0800 Thread[67540:402135] 請求2 結束 !!!
2018-02-01 17:55:45.013673+0800 Thread[67540:402134] 請求1 結束 !!!
2018-02-01 17:55:45.014906+0800 Thread[67540:402136] 請求3 結束 !!!

可以看到,group執(zhí)行結束代碼的時機是不確定的,這里請求還沒結束,group notify你面的代碼卻已經(jīng)執(zhí)行了.

下面來說下group notify 什么時候會調用:

  • 當所有的group中的代碼塊中的代碼從上至下執(zhí)行完成后就會調用notify.所以如果代碼塊中都是同步執(zhí)行的還好,如果出現(xiàn)了異步執(zhí)行的情況,因為即使是異步,當前代碼塊中的代碼仍然會往下繼續(xù)執(zhí)行.所以無論異步執(zhí)行的任務是否完成并不能起到?jīng)Q定作用.于是就出現(xiàn)了上面的問題.

  • 那我們如何來解決group中存在異步執(zhí)行代碼的情況呢.
    此時需用到 dispatch_group_enter() 和 dispatch_group_leave()
    上面代碼需要做如下修改

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    NSLog(@"group 開始執(zhí)行 !!!");
   
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"block1 begin !!!");
        [self request:1 block:^{
            dispatch_group_leave(group);
        }];
        NSLog(@"block1 end !!!");
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"block2 begin !!!");
        [self request:2 block:^{
            dispatch_group_leave(group);
        }];
        NSLog(@"block2 end !!!");
    });
    
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"block3 begin !!!");
        [self request:3 block:^{
            dispatch_group_leave(group);
        }];
        NSLog(@"block3 end !!!");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"group 結束 !!!");
    });

- (void)request:(NSInteger)count block:(void(^)(void))complete{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"請求%ld 開始 !!!", count);
        [NSThread sleepForTimeInterval:3];
         NSLog(@"請求%ld 結束 !!!", count);
        if(complete)
            complete();
    });
}

日志如下:

2018-04-04 10:57:03.655066+0800 Thread[13280:128963] group 開始執(zhí)行 !!!
2018-04-04 10:57:03.655381+0800 Thread[13280:129076] block1 begin !!!
2018-04-04 10:57:03.655385+0800 Thread[13280:129085] block2 begin !!!
2018-04-04 10:57:03.655445+0800 Thread[13280:129078] block3 begin !!!
2018-04-04 10:57:03.657045+0800 Thread[13280:129076] block1 end !!!
2018-04-04 10:57:03.657073+0800 Thread[13280:129079] 請求1 開始 !!!
2018-04-04 10:57:03.657078+0800 Thread[13280:129085] block2 end !!!
2018-04-04 10:57:03.657113+0800 Thread[13280:129078] block3 end !!!
2018-04-04 10:57:03.657184+0800 Thread[13280:129076] 請求2 開始 !!!
2018-04-04 10:57:03.657296+0800 Thread[13280:129085] 請求3 開始 !!!
2018-04-04 10:57:06.659375+0800 Thread[13280:129085] 請求3 結束 !!!
2018-04-04 10:57:06.659375+0800 Thread[13280:129076] 請求2 結束 !!!
2018-04-04 10:57:06.659403+0800 Thread[13280:129079] 請求1 結束 !!!
2018-04-04 10:57:06.659753+0800 Thread[13280:129076] group 結束 !!!

如上,結果和我們所期望的一致.在每一個異步任務開始之前,我們需要調用dispatch_group_enter(group)來防止block塊內代碼執(zhí)行完畢后,退出group.然后在異步請求響應后的回調里調用dispatch_group_leave(group)使其正常離開group就ok了.

dispatch_group_enter()和dispatch_group_leave()需要成對出現(xiàn)

GCD 柵欄方法:dispatch_barrier_async
  • 一般使用場景,我們開啟了多個異步任務.但是需要將其分組,并控制每組的執(zhí)行順序的時候可以使用該api
- (void)barrier {
    NSInteger count = 3;
    dispatch_queue_t queue = dispatch_queue_create("queue_label", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for(int i = 0; i < count; i++) {
            NSLog(@"Thread1 --> %d", i);
        }
    });
    
    dispatch_async(queue, ^{
        for(int i = 0; i < count; i++) {
            NSLog(@"Thread2 --> %d", i);
        }
    });
    
    dispatch_barrier_async(queue, ^{
        for(int i = 0; i < count; i++) {
            NSLog(@"barrier --> %d", i);
        }
    });
    
    dispatch_async(queue, ^{
        for(int i = 0; i < count; i++) {
            NSLog(@"Thread3 --> %d", i);
        }
    });
}

日志如下:

2018-04-04 14:38:29.095615+0800 Thread[15169:299036] Thread2 --> 0
2018-04-04 14:38:29.095611+0800 Thread[15169:298974] Thread1 --> 0
2018-04-04 14:38:29.095876+0800 Thread[15169:299036] Thread2 --> 1
2018-04-04 14:38:29.095876+0800 Thread[15169:298974] Thread1 --> 1
2018-04-04 14:38:29.096505+0800 Thread[15169:299036] Thread2 --> 2
2018-04-04 14:38:29.096861+0800 Thread[15169:298974] Thread1 --> 2
2018-04-04 14:38:29.097109+0800 Thread[15169:298974] barrier --> 0
2018-04-04 14:38:29.097212+0800 Thread[15169:298974] barrier --> 1
2018-04-04 14:38:29.097304+0800 Thread[15169:298974] barrier --> 2
2018-04-04 14:38:29.097414+0800 Thread[15169:298974] Thread3 --> 0
2018-04-04 14:38:29.097504+0800 Thread[15169:298974] Thread3 --> 1
2018-04-04 14:38:29.097908+0800 Thread[15169:298974] Thread3 --> 2

可以看出barrier之前的任務會先執(zhí)行,barrier之后的代碼會后執(zhí)行.barrier顧名思義起到了一個分割的作用.

GCD掛起和恢復
  • dispatch_suspend()掛起某一個隊列,并不是真正意義上的停止,已經(jīng)開始執(zhí)行的代碼塊是不會停止的.只會停止執(zhí)行還未執(zhí)行的block代碼塊
  • dispatch_resume()恢復隊列任務的執(zhí)行.和suspend成對出現(xiàn).
- (void)suspend {
    dispatch_queue_t queue = dispatch_queue_create("com.test.gcd", DISPATCH_QUEUE_SERIAL);
    //提交第一個block非驮,延時5秒打印。
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"五秒后打印雏赦,隊列掛起時已經(jīng)開始執(zhí)行劫笙,");
    });
    //提交第二個block,也是延時5秒打印
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"隊列掛起時未執(zhí)行星岗,需恢復隊列后在執(zhí)行");
    });
    //延時一秒
    NSLog(@"立刻打印~~~~~~~");
    [NSThread sleepForTimeInterval:1];
    //掛起隊列
    NSLog(@"一秒后打印填大,隊列掛起");
    dispatch_suspend(queue);
    //延時10秒
    [NSThread sleepForTimeInterval:11];
    NSLog(@"十秒后打印,開啟隊列");
    //恢復隊列
    dispatch_resume(queue);
}

日志如下:

2018-04-04 16:46:12.574933+0800 Thread[17344:474988] 立刻打印~~~~~~~
2018-04-04 16:46:13.576395+0800 Thread[17344:474988] 一秒后打印俏橘,隊列掛起
2018-04-04 16:46:17.576697+0800 Thread[17344:475108] 五秒后打印允华,隊列掛起時已經(jīng)開始執(zhí)行,
2018-04-04 16:46:24.577738+0800 Thread[17344:474988] 十秒后打印寥掐,開啟隊列
2018-04-04 16:46:29.583528+0800 Thread[17344:475104] 隊列掛起時未執(zhí)行靴寂,需恢復隊列后在執(zhí)行
GCD 快速迭代方法:dispatch_apply

類似for循環(huán),可以用來遍歷

- (void)apply {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) {
        NSLog(@"%zd", index);
    });
    NSLog(@"遍歷結束 !!!");
}

日志如下:

2018-04-04 17:11:42.159210+0800 Thread[18256:512357] 1
2018-04-04 17:11:42.159218+0800 Thread[18256:512356] 2
2018-04-04 17:11:42.159241+0800 Thread[18256:512358] 3
2018-04-04 17:11:42.159210+0800 Thread[18256:512257] 0
2018-04-04 17:11:42.159453+0800 Thread[18256:512357] 4
2018-04-04 17:11:42.159453+0800 Thread[18256:512358] 5
2018-04-04 17:11:42.159454+0800 Thread[18256:512356] 6
2018-04-04 17:11:42.159465+0800 Thread[18256:512257] 7
2018-04-04 17:11:42.159568+0800 Thread[18256:512357] 8
2018-04-04 17:11:42.159741+0800 Thread[18256:512358] 9
2018-04-04 17:11:42.160506+0800 Thread[18256:512257] 遍歷結束 !!!
  • 這里不是有序遍歷是因為,我們上面創(chuàng)建的是一個全局隊列,是異步執(zhí)行的.所以順序是隨機的.如果想要順序遍歷,可以創(chuàng)建一個串行隊列.

附:demo地址

未完待續(xù)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市召耘,隨后出現(xiàn)的幾起案子百炬,更是在濱河造成了極大的恐慌,老刑警劉巖污它,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剖踊,死亡現(xiàn)場離奇詭異,居然都是意外死亡衫贬,警方通過查閱死者的電腦和手機蜜宪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祥山,“玉大人圃验,你說我怎么就攤上這事》炫唬” “怎么了澳窑?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸡捐。 經(jīng)常有香客問我煎源,道長歇僧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任柄错,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘毫捣。我一直安慰自己蹲诀,他們只是感情好则北,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布快骗。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天偶妖,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的变隔。 我是一名探鬼主播猖闪,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肌厨!你這毒婦竟也來了培慌?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柑爸,失蹤者是張志新(化名)和其女友劉穎吵护,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體表鳍,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡馅而,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了譬圣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓮恭。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厘熟,靈堂內的尸體忽然破棺而出屯蹦,到底是詐尸還是另有隱情,我是刑警寧澤绳姨,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布登澜,位于F島的核電站,受9級特大地震影響飘庄,放射性物質發(fā)生泄漏脑蠕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一竭宰、第九天 我趴在偏房一處隱蔽的房頂上張望空郊。 院中可真熱鬧份招,春花似錦切揭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春孕豹,著一層夾襖步出監(jiān)牢的瞬間涩盾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工励背, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留春霍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓叶眉,卻偏偏與公主長得像址儒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衅疙,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內容

  • 背景 擔心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了莲趣!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似饱溢。...
    Dely閱讀 9,239評論 21 42
  • 1. GCD簡介 什么是GCD呢喧伞?我們先來看看百度百科的解釋簡單了解下概念 引自百度百科:Grand Centra...
    千尋_544f閱讀 367評論 0 0
  • 本篇博客共分以下幾個模塊來介紹GCD的相關內容: 多線程相關概念 多線程編程技術的優(yōu)缺點比較? GCD中的三種隊列...
    有夢想的老伯伯閱讀 1,020評論 0 4
  • 今天在網(wǎng)絡上看到了一個視頻片段绩郎,應該是一部電視劇還是電影里的潘鲫,沒有找到具體的出處∷陨希看完以后隨便寫了點字次舌,視頻里的對...
    枯葉草迷圖閱讀 779評論 1 2
  • 走在金州和平路和三里橋市場的這段路上,我看到的是讓人發(fā)指的惡心兽愤,路邊堆積如山的蒜皮彼念,這個地方離金州規(guī)劃最好的...
    然其閱讀 217評論 0 2