关于多线程之GCD的一些学习要点
GCD是當(dāng)前多線程使用最方便的,也是使用比較多的。
學(xué)習(xí)GCD主要集中在一下幾點:
一、隊列,同步,異步
1.主隊列:dispatch_get_main_queue();
2.串行隊列:dispatch_queue_create("queue", 0);
3.并行隊列:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4.同步,異步就不需要再多說什么。
?
對上面關(guān)鍵詞的一些解釋:
主隊列:主隊列只能使用異步來執(zhí)行隊列中的任務(wù),使用同步的話會造成死循環(huán)。同時執(zhí)行任務(wù)的時候是在主線程中執(zhí)行的。
串行隊列:(1)、添加到串行隊列中的任務(wù)是一個接著一個執(zhí)行的,也就是當(dāng)上一個任務(wù)執(zhí)行完之后才開始下一個任務(wù);
??????????????????????? 但是可以創(chuàng)建多個串行隊列,每個串行隊列之間是相互獨(dú)立的,可以并發(fā)執(zhí)行。
???????????? ?(2)、如果用同步執(zhí)行的話就是在當(dāng)前線程上執(zhí)行;
????????????? (3)、如果用異步執(zhí)行的話就是新開辟一個線程執(zhí)行。
并行隊列:(1)、添加到并行隊列中的任務(wù)可以并發(fā)啟動,啟動順序仍然是一個接著一個,但是后者可以不等前者執(zhí)行完就可以開始執(zhí)行。
??????????????????????? 并行隊列也可以創(chuàng)建多個,各個之間也是相互獨(dú)立,并發(fā)執(zhí)行的。
???????????? ?(2)、如果用同步執(zhí)行的話就是在當(dāng)前線程上執(zhí)行;
????????????? (3)、如果用異步執(zhí)行的話就是新開辟一個線程執(zhí)行。
????????????
二、經(jīng)常用到的地方
1.任務(wù)執(zhí)行完畢之后再進(jìn)行一些操作
2.只執(zhí)行一次
3.延時操作
?
對上面用處的一些解釋:
(1)、任務(wù)執(zhí)行完畢之后再進(jìn)行一些操作,如果是一些簡單的操作可以直接使用串行隊列實現(xiàn)。但是一些比較費(fèi)時的操作就需要用到隊列組了。
??? //1.創(chuàng)建一個隊列組
??????? dispatch_group_t group = dispatch_group_create();
????
??? //2.開啟一個任務(wù)1
??? dispatch_group_async(group, global_quque, ^{
?
??? });
????
??? //3.開啟一個任務(wù)2
??? dispatch_group_async(group, global_quque, ^{
?????? });
????
?? //4.等group中的所有任務(wù)都執(zhí)行完畢, 再回到主線程執(zhí)行其他操作
??? dispatch_group_notify(group,main_queue, ^{
???? });
????
?
(2)、只執(zhí)行一次
????????? static dispatch_once_t onceToken;
????????? dispatch_once(&onceToken, ^{
????? ??? // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});
?
(3)、延時操作
????????? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
??????? ? //延遲執(zhí)行的方法
??? });
?
(4)、暫停和恢復(fù)隊列中的任務(wù)
dispatch_suspend和dispatch_resume
我們知道NSOperationQueue有暫停(suspend)和恢復(fù)(resume)。其實GCD中的隊列也有類似的功能。用法也非常簡單:
dispatch_suspend(queue)?//暫停某個隊列 ?
dispatch_resume(queue)??//恢復(fù)某個隊列 ?
這些函數(shù)不會影響到隊列中已經(jīng)執(zhí)行的任務(wù),隊列暫停后,已經(jīng)添加到隊列中但還沒有執(zhí)行的任務(wù)不會執(zhí)行,直到隊列被恢復(fù)。
?
(5)、承上啟下
dispatch_async(queue, block1_for_reading) ?
dispatch_async(queue, block2_for_reading)
?
dispatch_barrier_async(queue, block_for_writing)
?
dispatch_async(queue, block3_for_reading) ?
dispatch_async(queue, block4_for_reading) ?
dispatch_barrier_async?會把并行隊列的運(yùn)行周期分為這三個過程:
總的來說,dispatch_barrier_async?起到了“承上啟下”的作用。它保證此前的任務(wù)都先于自己執(zhí)行,此后的任務(wù)也遲于自己執(zhí)行。正如barrier的含義一樣,它起到了一個柵欄、或是分水嶺的作用。
這樣一來,使用并行隊列和?dispatc_barrier_async?方法,就可以高效的進(jìn)行數(shù)據(jù)和文件讀寫了。
?
(6)、信號量
dispatch_semaphore
首先介紹一下信號量(semaphore)的概念。信號量是持有計數(shù)的信號,不過這么解釋等于沒解釋。我們舉個生活中的例子來看看。
假設(shè)有一個房子,它對應(yīng)進(jìn)程的概念,房子里的人就對應(yīng)著線程。一個進(jìn)程可以包括多個線程。這個房子(進(jìn)程)有很多資源,比如花園、客廳等,是所有人(線程)共享的。
但是有些地方,比如臥室,最多只有兩個人能進(jìn)去睡覺。怎么辦呢,在臥室門口掛上兩把鑰匙。進(jìn)去的人(線程)拿著鑰匙進(jìn)去,沒有鑰匙就不能進(jìn)去,出來的時候把鑰匙放回門口。
這時候,門口的鑰匙數(shù)量就稱為信號量(Semaphore)。很明顯,信號量為0時需要等待,信號量不為零時,減去1而且不等待。
在GCD中,創(chuàng)建信號量的語法如下:
var?semaphore = dispatch_semaphore_create(2) ?
這句代碼通過?dispatch_semaphore_create?方法創(chuàng)建一個信號量并設(shè)置初始值為 2。然后就可以調(diào)用?dispatch_semaphore_wait?方法了。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) ?
dispatch_semaphore_wait?方法表示一直等待直到信號量的值大于等于 1,當(dāng)這個方法執(zhí)行后,會把第一個信號量參數(shù)的值減 1。
第二個參數(shù)是一個?dispatch_time_t?類型的時間,它表示這個方法最大的等待時間。這在第一章中已經(jīng)講過,比如?DISPATCH_TIME_FOREVER?表示永久等待。
返回值也和?dispatch_group_wait?方法一樣,返回 0 表示在規(guī)定的等待時間內(nèi)第一個參數(shù)信號量的值已經(jīng)大于等于 1,否則表示已超過規(guī)定等待時間,但信號量的值還是 0。
dispatch_semaphore_wait?方法返回 0,因為此時的信號量的值大于等于一,任務(wù)獲得了可以執(zhí)行的權(quán)限。這時候我們就可以安全的執(zhí)行需要進(jìn)行排他控制的任務(wù)了。
任務(wù)結(jié)束時還需要調(diào)用?dispatch_semaphore_signal()?方法,將信號量的值加 1。這類似于之前所說的,從臥室出來要把鎖放回門上,否則后來的人就無法進(jìn)入了。
我們來看一個完整的例子:
var?semaphore = dispatch_semaphore_create(1) ?
let?queue = dispatch_queue_create("com.gcd.kt", DISPATCH_QUEUE_CONCURRENT) ?
var?array: [Int] = []
?
for?i?in?1...100000?{ ?
? ? dispatch_async(queue, { () -> Void?in
? ? ? ??/*
? ? ? ? ? ? 某個線程執(zhí)行到這里,如果信號量值為1,那么wait方法返回1,開始執(zhí)行接下來的操作。
? ? ? ? ? ? 與此同時,因為信號量變?yōu)?,其它執(zhí)行到這里的線程都必須等待
? ? ? ? */
? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
?
? ? ? ??/*
? ? ? ? ? ? 執(zhí)行了wait方法后,信號量的值變成了0。可以進(jìn)行接下來的操作。
? ? ? ? ? ? 這時候其它線程都得等待wait方法返回。
? ? ? ? ? ? 可以對array修改的線程在任意時刻都只有一個,可以安全的修改array
? ? ? ? */
? ? ? ? array.append(i)
?
? ? ? ??/*
? ? ? ? ? ? 排他操作執(zhí)行結(jié)束,記得要調(diào)用signal方法,把信號量的值加1。
? ? ? ? ? ? 這樣,如果有別的線程在等待wait函數(shù)返回,就由最先等待的線程執(zhí)行。
? ? ? ? */
? ? ? ? dispatch_semaphore_signal(semaphore)
? ? })
}
?
總結(jié):
1、常用的延時操作:
??? (1)????dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
??????? ? //延遲執(zhí)行的方法
??? });
??? (2) ? [self performSelector:@selector(test) withObject:nil afterDelay:1.0];
2、回到主線程的操作:
??? (1)??? dispatch_async(dispatch_get_main_queue(), ^{
?????????????? // 回到主線程,執(zhí)?UI刷新操作 });
??? (2)??? [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
?
轉(zhuǎn)載于:https://www.cnblogs.com/danMing-love/p/5598361.html
總結(jié)
以上是生活随笔為你收集整理的关于多线程之GCD的一些学习要点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈理工OJ—1598【DP最长公共子序列
- 下一篇: 类的设计