国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Objective-C 多線程

2019-11-09 19:06:21
字體:
供稿:網(wǎng)友

我們介紹多線程首先我們需要一些基礎(chǔ)知識(shí)一下我們一一介紹

進(jìn)程

進(jìn)程:指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,每個(gè)進(jìn)程是獨(dú)立,每個(gè)京城都運(yùn)行在其專用受保護(hù)的內(nèi)存空間。這也就是說多進(jìn)程要比多線程健壯我們之后介紹。

線程

線程:是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程的所有任務(wù)都在線程中執(zhí)行,在一個(gè)線程中任務(wù)都是串行(順序執(zhí)行)。

線程通信

線程通信:在一個(gè)進(jìn)程中,線程往往不是孤立存在的,多個(gè)線程之間需要經(jīng)常進(jìn)行通信,比如一個(gè)線程傳遞數(shù)據(jù)給另一個(gè)線程,執(zhí)行完一個(gè)線程的任務(wù)后在執(zhí)行另一個(gè)線程。

多線程

多線程:一個(gè)進(jìn)程中開啟多條線程,每條線程并發(fā)(同時(shí))執(zhí)行不同的任務(wù),多線程可以提高程序的執(zhí)行效率。

原理

同一時(shí)間,CPU只能處理1條線程,只有1條線程在工作(執(zhí)行),多線程并發(fā)(同時(shí))執(zhí)行,其實(shí)是CPU快速地在多條線程之間調(diào)度(切換),如果CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程并發(fā)執(zhí)行的假象。同樣如果頻繁的切換線程,使得CPU在N個(gè)線程之間調(diào)度,消耗大量的的CPU資源使得線程的執(zhí)行效率降低,多線程開發(fā)我們要找到平衡點(diǎn),控制線程的數(shù)量。

優(yōu)點(diǎn)

提高程序的執(zhí)行效率,不會(huì)因?yàn)橐恍┖臅r(shí)操作影響其他功能正常運(yùn)行同時(shí)還可以提高資源利用率,CPU和內(nèi)存的利用率。

缺點(diǎn)

開啟線程會(huì)占用一定的內(nèi)存空間,如果大量的開啟線程會(huì)占用大量的內(nèi)存空間,同時(shí)CPU在調(diào)度線程上也會(huì)占用資源,在程序設(shè)計(jì)會(huì)變得復(fù)雜,線程的通信和數(shù)據(jù)的共享等等。

iOS的多線程的實(shí)現(xiàn)目前有4種:Pthread, NSThread, GCD, NSOperation,以下我們分別介紹。

Pthread

Pthread是一套通用的API,多個(gè)平臺(tái)支持,它是基于C語言的,線程的生命周期需要我們手動(dòng)管理,使用難度大,平時(shí)開發(fā)基本不用。我們還是來一個(gè)簡(jiǎn)單的例子

//創(chuàng)建一個(gè)線程并自動(dòng)執(zhí)行 pthread_create(&thread, NULL, start, NULL);

NSThread

NSThread是Objective-C對(duì)C語言Pthread的封裝,面向?qū)ο蠛?jiǎn)單易用,可直接操作線程對(duì)象,同樣生命周期需要我們管理。開發(fā)中不常使用,以下是對(duì)NSThread方法得說明。

創(chuàng)建、啟動(dòng)線程N(yùn)SThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];[thread start];主線程相關(guān)用法+ (NSThread *)mainThread; // 獲得主線程- (BOOL)isMainThread; // 是否為主線程+ (BOOL)isMainThread; // 是否為主線程獲得當(dāng)前線程 NSThread *current = [NSThread currentThread];線程的名字- (void)setName:(NSString *)n;- (NSString *)name;線程的調(diào)度優(yōu)先級(jí),調(diào)度優(yōu)先級(jí)的取值范圍是0.0 ~ 1.0,默認(rèn)0.5,值越大,優(yōu)先級(jí)越高+ (double)threadPRiority;+ (BOOL)setThreadPriority:(double)p;- (double)threadPriority;- (BOOL)setThreadPriority:(double)p;創(chuàng)建線程后自動(dòng)啟動(dòng)線程[NSThread detachNewThreadSelector:@selector(test) toTarget:self withObject:nil];隱式創(chuàng)建并啟動(dòng)線程[self performSelectorInBackground:@selector(test) withObject:nil];控制線程狀態(tài)//啟動(dòng)線程- (void)start; //阻塞(暫停)線程+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;//強(qiáng)制停止線程+ (void)exit;//線程停止了,就不能再次開啟任務(wù)

-線程間通信常用方法

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

GCD

GCD全稱是Grand Central Dispatch,蘋果公司為多核的并行運(yùn)算提出的解決方案,會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核),會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程),雖然是純C語言,基于Block實(shí)現(xiàn),但是使用起來非常方便。想要更深的了解GCD就必須知道任務(wù)和隊(duì)列。

任務(wù)

任務(wù):就是需要執(zhí)行的操作,我們可以定制任務(wù),任務(wù)的執(zhí)行分為同步執(zhí)行異步執(zhí)行,區(qū)別在于是否開啟新的線程。

同步執(zhí)行

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

異步執(zhí)行

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

隊(duì)列

隊(duì)列:就是用來存放任務(wù),把我們定制的任務(wù)存放在隊(duì)列中,GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出,放到對(duì)應(yīng)的線程中執(zhí)行,任務(wù)的取出遵循隊(duì)列FIFO原則:先進(jìn)先出,后進(jìn)后出。隊(duì)列分為兩大類型:并發(fā)隊(duì)列和串行隊(duì)列。

并發(fā)隊(duì)列 可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效,GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用,不需要手動(dòng)創(chuàng)建

使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, // 隊(duì)列的優(yōu)先級(jí)unsigned long flags); // 此參數(shù)暫時(shí)無用,用0即可dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發(fā)隊(duì)列/*全局并發(fā)隊(duì)列的優(yōu)先級(jí)#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)*/

串行隊(duì)列 讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)),GCD中獲得串行有2種

1.使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列

dispatch_queue_tdispatch_queue_create(const char *label, // 隊(duì)列名稱 dispatch_queue_attr_t attr); // 隊(duì)列屬性,一般用NULL即可dispatch_queue_t queue = dispatch_queue_create("first", NULL); // 創(chuàng)建dispatch_release(queue); // 非ARC需要釋放手動(dòng)創(chuàng)建的隊(duì)列

2.使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列),是GCD自帶的一種特殊的串行隊(duì)列,主隊(duì)列的任務(wù)都會(huì)放在主線程中執(zhí)行,使用dispatch_get_main_queue()獲得主隊(duì)列

dispatch_queue_t queue = dispatch_get_main_queue();

任務(wù)隊(duì)列執(zhí)行

我們對(duì)任務(wù)同步異步和隊(duì)列串行并發(fā)的執(zhí)行分析

串行隊(duì)列同步執(zhí)行:不開線程,在原來的線程順序執(zhí)行dispatch_queue_t queue = dispatch_queue_create("cs",DISPATCH_QUEUE_SERIAL);dispatch_sync(queue,^{ //串行隊(duì)列,同步執(zhí)行,不開線程,順序執(zhí)行});串行隊(duì)列異步執(zhí)行:開一條線程,在線程中順序執(zhí)行,效率低占用資源少(相對(duì)比較)dispatch_queue_t queue = dispatch_queue_create("cs",DISPATCH_QUEUE_SERIAL);dispatch_async(queue,^{ //串行隊(duì)列,異步執(zhí)行,開一條線程,順序執(zhí)行});并發(fā)隊(duì)列同步執(zhí)行:不開線程,同步執(zhí)行//并發(fā)隊(duì)列dispatch_queue_t queue = dispatch_queue_create("bs",DISPATHCH_QUEUE_CONCURRENT);dispatch_sync(queue,^{//先執(zhí)行同步任務(wù),不開線程});dispatch_async(queue,^{//等到同步任務(wù)執(zhí)行完成后,開啟線程執(zhí)行當(dāng)前操作});dispatch_async(queue,^{//等到同步任務(wù)執(zhí)行完成后,開啟線程執(zhí)行當(dāng)前操作});并發(fā)隊(duì)列異步執(zhí)行:開第一個(gè)線程,并發(fā)執(zhí)行,效率高占用資源大//并發(fā)隊(duì)列dispatch_queue_t queue = dispatch_queue_create("ba",DISPATHCH_QUEUE_CONCURRENT);dispatch_async(queue,^{//開啟線程執(zhí)行當(dāng)前操作});dispatch_async(queue,^{//開啟線程執(zhí)行當(dāng)前操作});

線程通信

dispatch_async(dispatch_get_global_queue(0,0),^{ //耗時(shí)操作,代碼…… //回到主線程執(zhí)行操作 dispatch_async(dispatch_get_main_queue(),^{ //回到主線程,代碼…… });});

延時(shí)執(zhí)行

1.調(diào)用NSObject方法

//2秒后調(diào)用[self performSelector:@selector(run) withObject:nil afterDelay:2.0];

2.使用GCD函數(shù)

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后異步執(zhí)行這里的代碼...});

一次性代碼

使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次

static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{ // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)});

隊(duì)列組

可以管理組內(nèi)的隊(duì)列執(zhí)行情況,方便對(duì)線程管理,比如我們異步執(zhí)行兩個(gè)耗時(shí)的操作,等待完成后回到主線程執(zhí)行操作

dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執(zhí)行1個(gè)耗時(shí)的異步操作});dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執(zhí)行1個(gè)耗時(shí)的異步操作});dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 等前面的兩個(gè)異步操作都執(zhí)行完畢后,回到主線程...});

NSOperation

NSOperation:是基于GCD實(shí)現(xiàn)的,比GCD多了更加簡(jiǎn)單實(shí)用的功能,更加面向?qū)ο蟆E浜鲜褂肗SOperation和NSOperationQueue實(shí)現(xiàn)多線程編程,我們開發(fā)中經(jīng)常使用。

實(shí)現(xiàn)步驟

先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中然后將NSOperation對(duì)象添加到NSOperationQueue中系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行

NSOperationQueue

提供兩種隊(duì)列:主隊(duì)列和全局并發(fā)隊(duì)列

主隊(duì)列

NSOperationQueue *queue = [[NSOperationQueue mainQueue];

全局并發(fā)隊(duì)列

NSOperationQueue *queue = [[NSOperationQueue alloc]init];

添加任務(wù)

//1.添加一個(gè)NSOperation的子類- (void); addOperation:(NSOperation *)op[queue addOperation:op];//2.添加一個(gè)Block- (void)addOperationWithBlock:(void (^)(void))block;[queue addOperationWithBlock:^{ //代碼}];

NSOperation

NSOperation是個(gè)抽象類,我們使用必須使用它的子類,使用NSOperation子類的方式有3種

1. NSInvocationOperation 對(duì)GCD中全局并發(fā)隊(duì)列的封裝

//1.創(chuàng)建操作NSOperation *op = [[NSInvocationOperation alloc] initWithTatger:self selecter:@Selector(downloadImage:) object:@"Invocation"];//2. 加入隊(duì)列中NSOperationQueue *queue = [[NSOperationQueue alloc]init];//異步執(zhí)行[queue addOperation:op];

2. NSBlockOperation對(duì)GCD中全局并發(fā)隊(duì)列的封裝

NSOperationQueue *queue = [[NSOperationQueue alloc]init];//添加任務(wù)NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ //需要執(zhí)行的操作}];//添加到隊(duì)列[queue addOperation:op];

3. 自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法

最大并發(fā)數(shù)

最大并發(fā)數(shù)就是同時(shí)執(zhí)行的任務(wù)數(shù),可以使用下面的方法

- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

隊(duì)列的操作

取消

- (void)cancelAllOperations;//也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作

暫停/恢復(fù)

// YES代表暫停隊(duì)列,NO代表恢復(fù)隊(duì)列- (void)setSuspended:(BOOL)b; - (BOOL)isSuspended;

操作優(yōu)先級(jí)

設(shè)置NSOperation在queue中的優(yōu)先級(jí),可以改變操作的執(zhí)行優(yōu)先級(jí)

- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p;/* 優(yōu)先級(jí)的取值 NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8*/

操作監(jiān)聽

可以監(jiān)聽一個(gè)操作的執(zhí)行完畢

- (void (^)(void))completionBlock;- (void)setCompletionBlock:(void (^)(void))block;

操作依賴

NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序,比如一定要讓操作A執(zhí)行完后,才能執(zhí)行操作B

// 操作B依賴于操作A[operationB addDependency:operationA];

多線程引發(fā)的問題

我們之前提到的原子性和非原子性,相信在這次的介紹中已經(jīng)有根深的理解了

1.資源共享:一個(gè)資源可能被多個(gè)線程共享,多線程訪問同一塊資源容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全

互斥鎖

用來防止兩個(gè)進(jìn)程或線程在同一時(shí)刻訪問相同的共享資源。

@synchronized(鎖對(duì)象) { // 需要鎖定的代碼 }

優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題 缺點(diǎn):需要消耗大量的CPU資源

死鎖

死鎖: 是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過程中,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。(在學(xué)校每次考試都考)

PS

今天寫了好長(zhǎng)時(shí)間,總結(jié)整理,眼睛感覺已經(jīng)不是自己的了,發(fā)現(xiàn)有不對(duì)的地方歡迎評(píng)論和聯(lián)系微博


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 文安县| 崇义县| 福州市| 青浦区| 同江市| 二连浩特市| 太谷县| 页游| 三台县| 宜丰县| 新建县| 阜宁县| 乌鲁木齐市| 庆阳市| 苍山县| 昆明市| 澳门| 墨江| 湖口县| 武定县| 彭水| 塘沽区| 千阳县| 太白县| 仙桃市| 仁化县| 益阳市| 扬州市| 马边| 铅山县| 江油市| 金门县| 宁陵县| 出国| 萝北县| 临潭县| 柳江县| 奉新县| 灵丘县| 阿瓦提县| 和龙市|