基于C接口的線程調(diào)度。
dispatch_queue_attr_t : 定義一個queue的時候,用于指定queue的類型,queue的類型決定了queue里面的任務(wù)執(zhí)行的順序
DISPATCH_QUEUE_SERIAL:queue里面的任務(wù)由單個線程順序執(zhí)行
DISPATCH_QUEUE_CONCURRENT:queue里面的任務(wù)并發(fā)執(zhí)行,一般由多個線程負責執(zhí)行。
DISPATCH_QUEUE_SERIAL_INACTIVE
DISPATCH_QUEUE_CONCURRENT_INACTIVE:INACTIVE結(jié)尾的queue,往queue里面派發(fā)任務(wù)之前,必須先調(diào)用dispatch_activate(queue);
DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL
DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL
dispatch_async VS dispatch_sync
dispatch_async(queue, block);不阻塞當前線程。
dispatch_sync(queue,block);阻塞當前線程,直到任務(wù)執(zhí)行完畢。如果當前線程是主線程,queue又是main_queue,那么主線程會被卡死。
系統(tǒng)提供的兩個重要的queue
dispatch_queue_t? main_queue = dispatch_get_main_queue(); 主線程維護的全局可用的串行隊列,這個隊列與主線程的runLoop一起工作。
dispatch_queue_t global_queue = dispatch_get_global_queue(long identifier,unsigned long flags)。
identifer:可以使用qos_class_t中定義的服務(wù)質(zhì)量類或dispatch_queue_priority_t中定義的優(yōu)先級。
__QOS_ENUM(qos_class, unsigned int,
QOS_CLASS_USER_INTERACTIVE
__QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) =0x21,
QOS_CLASS_USER_INITIATED
QOS_CLASS_DEFAULT
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND
QOS_CLASS_UNSPECIFIED
);
typedef long dispatch_queue_priority_t;
參數(shù)flags:現(xiàn)階段暫時用不到,一般傳 0。
dispatch_time_t:設(shè)定一個調(diào)度時間。
方法1: dispatch_time_t? dispatchTime = dispatch_time(dispatch_time_t when, int64_t delta);
兩個特殊的dispatch_time_t。
DISPATCH_TIME_NOW
DISPATCH_TIME_FOREVER
#define NSEC_PER_SEC 1000000000ull // 1s
#define NSEC_PER_MSEC 1000000ull // 1ms
#define USEC_PER_SEC 1000000ull // 1ms
#define NSEC_PER_USEC 1000ull // 1μm
//舉例,表示距離現(xiàn)在10秒后時間點
dispatch_time_t newTime = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
方法2:dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);
舉個栗子:
NSString * dateString = @"2018-08-08 08:08:08";
NSDateFormatter * formatDate = [[NSDateFormatter alloc] init];
formatDate.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate * yearDate = [formatDate dateFromString:dateString];
NSTimeInterval interval = [yearDate timeIntervalSince1970];
double second, subSecond;
struct timespec time;
// 將浮點數(shù)分解為整數(shù)和小數(shù)
subSecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subSecond * NSEC_PER_SEC;
dispatch_time_t absoluteTime = dispatch_walltime(&time, 8 * NSEC_PER_SEC);
dispatch做延遲
dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
dispatch_after函數(shù)不是在指定時間后執(zhí)行某種處理,而只是在指定時間將某種處理追加到Dispatch Queue中,但是不一定是立即執(zhí)行該處理!
dispatch_group_t:調(diào)度組。
GCD提供兩種方式支持dispatch并發(fā)隊列中的任務(wù)同步,即dispatch group和dispatch semaphore。
出現(xiàn)背景:并發(fā)隊列中的多個任務(wù),在線程池里面并發(fā)執(zhí)行的時候,需要知道所有任務(wù)執(zhí)行完成的時機,以便做一些處理。因此,dispatch_group_t一般作用于并發(fā)隊列。而串行隊列單線程順序執(zhí)行則不存在這種需求。
dispatch_group_t? group =dispatch_group_create();
dispatch_group_async(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull cocurentQueue, ^{
});
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);:該函數(shù)會一直等到組關(guān)聯(lián)的所有任務(wù)塊都已完成,然后再會將本函數(shù)將執(zhí)行的Block追加到Dispatch Queue中!
int state = dispatch_group_wait(group,dispatch_time(DISPATCH_TIME_NOW,0.000000000001*NSEC_PER_SEC));
group里面的任務(wù)執(zhí)行時間超過timeout后,state返回不為0,但是group里面的任務(wù)并沒有撤銷,而是繼續(xù)執(zhí)行。這個state只能反映出任務(wù)在timeout的時間內(nèi)是否能夠執(zhí)行完,而不能夠使得超時的任務(wù)撤銷。
還有兩個接口注意下。
下面的兩種調(diào)用其實是等價的,
A) dispatch_group_async(group, queue, ^{ // 。。。 });
B) dispatch_group_enter(group);
dispatch_async(queue, ^{ //。。。 dispatch_group_leave(group); });
下面是一個例子。
dispatch_group_t newGroup = dispatch_group_create();
dispatch_queue_t queue_change = dispatch_queue_create("com.atx610.NewMTX.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(newGroup, queue_change, ^{
sleep(1);
NSLog(@"test_1");
});
dispatch_group_async(newGroup, queue_change, ^{
NSLog(@"test_2");
});
dispatch_group_enter(newGroup);
dispatch_async(queue_change, ^{
NSLog(@"test_3");
dispatch_group_leave(newGroup);
});
dispatch_group_enter(newGroup);
dispatch_async(queue_change, ^{
sleep(2);
NSLog(@"test_4");
dispatch_group_leave(newGroup);
});
dispatch_group_notify(newGroup, queue_change, ^{
NSLog(@"done,and start new work");
});
//? ? dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
//? ? long result = dispatch_group_wait(newGroup, time);
//? ? if (result == 0) {
//? ? ? ? NSLog(@"在設(shè)置的時間內(nèi),組中的任務(wù)全部完成");
//? ? }else{
//? ? ? ? NSLog(@"在設(shè)置的時間內(nèi),組中的任務(wù)未全部完成");
//? ? }
調(diào)度墻:Dispatch Barrier
應(yīng)用場景:并發(fā)隊列中有若干個任務(wù),用戶希望這些任務(wù)能夠分批進行,一批結(jié)束,做一些操作或者不做任何操作,接著進行下一批。
注意事項:當提交到全局隊列(global queue)或未使用DISPATCH_QUEUE_CONCURRENT屬性創(chuàng)建的隊列時,Barrier Block與其他任務(wù)中的Block的行為相同!
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //異步執(zhí)行障礙Block?
void dispatch_barrier_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);//同步執(zhí)行障礙Block?
與調(diào)用次數(shù)相關(guān)的接口:
void dispatch_apply(size_t iterations, dispatch_queue_t queue, DISPATCH_NOESCAPE void (^block)(size_t));:第一個參數(shù)iterations表示重復次數(shù),第三個參數(shù)block中有一個參數(shù),表示該block按照重復次數(shù)添加到queue中時是第幾個添加的。
void dispatch_once(dispatch_once_t *predicate, DISPATCH_NOESCAPE dispatch_block_t block);
信號量:dispatch semaphore
信號量解決的是一個車位不夠用的問題:
其中有3個重要接口:
1,dispatch_samaphore_t dispatch_semaphore_create(long value);
傳入的參數(shù)為long,輸出一個dispatch_semaphore_t類型且值為value的信號量。
值得注意的是,這里的傳入的參數(shù)value必須大于或等于0,否則dispatch_semaphore_create會返回NULL。
2,long dispatch_semaphore_wait(dispatch_semaphore_t ?dsema, dispatch_time_t timeout);
消費一個車位,timeout用于設(shè)定等車位的時間,超過后就不再等待了。
3,long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
增加一個車位。
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semap = dispatch_semaphore_create(0);
dispatch_async(global, ^{
dispatch_semaphore_wait(semap, DISPATCH_TIME_FOREVER);
NSLog(@"first");
});
NSLog(@"second");
dispatch_semaphore_signal(semap);
output:
second
first
掛起和繼續(xù)執(zhí)行一個queue
dispatch_suspend(queue);
dispatch_resume(queue);
以上兩個要成對出現(xiàn),出現(xiàn)suspend,一定要有一個resume,不能無限制掛起。否則,會崩潰。