iOS 多線程基礎(chǔ)學(xué)習(xí)

1252638-9184f4909ab2f2d1.png

1.基本概念

  • 進(jìn)程: 一個具有一定獨(dú)立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運(yùn)行活動。可以理解成一個運(yùn)行中的應(yīng)用程序。

  • 線程: 程序執(zhí)行流的最小單元,線程是進(jìn)程中的一個實(shí)體。

  • 同步: 只能在當(dāng)前線程按先后順序依次執(zhí)行,不開啟新線程。

  • 異步: 可以在當(dāng)前線程開啟多個新線程執(zhí)行,可不按順序執(zhí)行

  • 隊(duì)列: 裝載線程任務(wù)的隊(duì)形結(jié)構(gòu)。

  • 并發(fā): 線程執(zhí)行可以同時一起進(jìn)行執(zhí)行。

  • 串行: 線程執(zhí)行只能依次逐一先后有序的執(zhí)行。

  • 一個進(jìn)程可以有多個線程,也可以有多個隊(duì)列

2.iOS多線程對比

  1. NSThread
    每個NSThread對象對應(yīng)一個線程,真正最原始的線程。
    1)優(yōu)點(diǎn):NSThread 輕量級最低,相對簡單。
    2)缺點(diǎn):手動管理所有的線程活動,如生命周期、線程同步、睡眠等。

  2. NSOperation
    自帶線程管理的抽象類。
    1)優(yōu)點(diǎn):自帶線程周期管理,操作上可更注重自己邏輯。
    2)缺點(diǎn):面向?qū)ο蟮某橄箢?,只能?shí)現(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。

  3. GCD
    Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的解決方法。
    1)優(yōu)點(diǎn):最高效,避開并發(fā)陷阱。
    2)缺點(diǎn):基于C實(shí)現(xiàn)。

  4. 選擇小結(jié)
    1)簡單而安全的選擇NSOperation實(shí)現(xiàn)多線程即可。
    2)處理大量并發(fā)數(shù)據(jù),又追求性能效率的選擇GCD。
    3)NSThread本人選擇基本上是在做些小測試上使用,當(dāng)然也可以基于此造個輪子。

3.場景選擇

圖片異步加載
這種常見的場景是最常見也是必不可少的。異步加載圖片有分成兩種來說明一下。

  • 第一種,在UI主線程開啟新線程按順序加載圖片,加載完成刷新UI。
  • 第二種,依然是在主線程開啟新線程,順序不定地加載圖片,加載完成個字刷新UI。

創(chuàng)作工具上的異步
這個跟上邊任務(wù)調(diào)度道理差不多,只是為了豐富描述,有助于“舉一反三”效果。如下描述的是app創(chuàng)作小說。

  • 場景一,app本地創(chuàng)作10個章節(jié)內(nèi)容未成同步服務(wù)器,接著同時發(fā)表這10個章節(jié)將產(chǎn)生的一系列動作,其中上傳內(nèi)容,獲取分配章節(jié)Id,如果后臺沒有做處理最好方式做異步按順序執(zhí)行。
  • 場景二,app本地創(chuàng)作列表中有3本小說要發(fā)表,如果同時發(fā)表創(chuàng)作列表中的3本小說,自然考慮并行隊(duì)列執(zhí)行發(fā)表。

4.使用方法

NSThread的使用
- (void)dynamicCreateThread
{
    //創(chuàng)建NSThread 動態(tài)
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
    thread.threadPriority = 1;
    [thread start];
}
- (void)staticCreateThread
{
    //創(chuàng)建靜態(tài)線程
    [NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
    
}
- (void)implicitCreateThread
{
    //隱式創(chuàng)建線程
    [self performSelectorInBackground:@selector(loadImage) withObject:self];
}

NSThread的拓展認(rèn)識
①獲取當(dāng)前線程

NSThread *current = [NSThread currentThread];

②獲取主線程

NSThread *main = [NSThread mainThread];

③暫停當(dāng)前線程

[NSThread sleepForTimeInterval:2];

④線程之間通信

//在指定線程上執(zhí)行操作
[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES]; 
//在主線程上執(zhí)行操作
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES]; 
//在當(dāng)前線程執(zhí)行操作
[self performSelector:@selector(run) withObject:nil];
NSOperation

主要的實(shí)現(xiàn)方式:結(jié)合NSOperation和NSOperationQueue實(shí)現(xiàn)多線程編程。
實(shí)例化NSOperation的子類,綁定執(zhí)行的操作。
創(chuàng)建NSOperationQueue隊(duì)列,將NSOperation實(shí)例添加進(jìn)來。
系統(tǒng)會自動將NSOperationQueue隊(duì)列中檢測取出和執(zhí)行NSOperation的操作。

使用NSOperation的子類實(shí)現(xiàn)創(chuàng)作線程。
①.NSInvocationOperation創(chuàng)建線程。

NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageSource:) object:imgUrl];
//[invocationOperation start];//直接會在當(dāng)前線程主線程執(zhí)行
NSOperationQueue *queue = [[NSOperationQueue alloc]init];[queue addOperation:invocationOperation];

②.NSBlockOperation創(chuàng)建線程

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 
       [self loadImageSource:imgUrl];
}];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:blockOperation];

GCD?

Grand Central Dispatch (GCD) 是 Apple 開發(fā)的一個多核編程的解決方法,GCD 是一個替代諸如 NSThread, NSOperationQueue, NSInvocationOperation 等技術(shù)的很高效和強(qiáng)大的技術(shù)。

分發(fā)隊(duì)列種類(dispatch queue)
①.UI主線程隊(duì)列 main queue

dispatch_get_main_queue()

②.并行隊(duì)列g(shù)lobal dispatch queue

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

這里的兩個參數(shù)得說明一下:第一個參數(shù)用于指定優(yōu)先級,分別使用DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW兩個常量來獲取高和低優(yōu)先級的兩個queue;第二個參數(shù)目前未使用到,默認(rèn)0即可

③.串行隊(duì)列serial queues

dispatch_queue_create("minggo.app.com", NULL);

6種多線程實(shí)現(xiàn)
①后臺執(zhí)行線程創(chuàng)建

dispatch_async(dispatch_get_global_queue(0, 0), ^{
 [self loadImageSource:imgUrl1];
});

②UI線程執(zhí)行(只是為了測試,長時間加載內(nèi)容不放在主線程)

dispatch_async(dispatch_get_main_queue(), ^{ 
[self loadImageSource:imgUrl1];
});

③一次性執(zhí)行(常用來寫單例)

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
 [self loadImageSource:imgUrl1];
});

④并發(fā)地執(zhí)行循環(huán)迭代

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 size_t count = 10;
 dispatch_apply(count, queue, ^(size_t i) { 
 NSLog(@"循環(huán)執(zhí)行第%li次",i);
 [self loadImageSource:imgUrl1];
});

⑤延遲執(zhí)行

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
[self loadImageSource:imgUrl1];
});

⑥自定義dispatch_queue_t

dispatch_queue_t urls_queue = dispatch_queue_create("minggo.app.com", NULL);
dispatch_async(urls_queue, ^{ 
[self loadImageSource:imgUrl1];
});

對比多任務(wù)執(zhí)行
異步加載圖片是大部分app都要面對的問題,那么加載圖片是按循序加載完之后才刷新UI呢?還是不安順序加載UI呢?顯然大部分的希望各自加載各自的圖片,各自刷新。以下就是模擬這兩種場景。
①先后執(zhí)行,加載兩張圖片為例

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
   UIImage *image1 = [self loadImage:imgUrl1]; 
   UIImage *image2 = [self loadImage:imgUrl2]; 

   dispatch_async(dispatch_get_main_queue(), ^{ 
     self.imageview1.image = image1; 
     self.imageView2.image = image2; 

     });
});

②并行隊(duì)列執(zhí)行,也是以加載兩張圖片為例

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_async(queue, ^{ dispatch_group_t group = dispatch_group_create();
   __block UIImage *image1 = nil; 
   __block UIImage *image2 = nil;

 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        image1 = [self loadImage:imgUrl1];
 }); 

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        image2 = [self loadImage:imgUrl2];
 }); 

dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
      self.imageview1.image = image1; 
      self.imageView2.image = image2; 
   });

});

①中等到兩張圖片加載完成后一起刷新,②就是典型的異步并行的例子,不需要理會各自圖片加載的先后問題,完成加載圖片刷新UI即可。從加載圖片中來說,第①種不太合適使用,但是對于在上邊場景選擇中的創(chuàng)作工具來說有很大的好處,首先得異步進(jìn)行,然后異步中有得按順序執(zhí)行幾個任務(wù),比如上傳章節(jié)內(nèi)容。因此,我們可以靈活考慮使用這兩多線程任務(wù)執(zhí)行方式,實(shí)現(xiàn)各種場景。

原文地址:http://www.lxweimin.com/p/6e6f4e005a0b

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 854評論 0 3
  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎樣m閱讀 1,302評論 0 1
  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序,每個進(jìn)程之間是獨(dú)立的,每個進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,521評論 1 33
  • 推酷誠意滿滿的技術(shù)周刊《編程狂人》第一七七期來了, 下面是內(nèi)容列表,干貨多多,也可以移步到官網(wǎng)進(jìn)一步閱讀。 前端開...
    推酷閱讀 701評論 0 1
  • 時隔幾天 再來簡書 寫點(diǎn)東西 一切真的已經(jīng)物是人非了~人家說放不下一個人的時候 想想他是怎么放下你的 可能你也就放了
    凈土ing閱讀 210評論 0 0