掃盲——>iOS中の多線程

今天被人問(wèn)到了下多線程方面的一些知識(shí),平時(shí)一直在用然后原 理不是理解得很透徹,所以今晚決定整理資料來(lái)個(gè)掃盲貼.開(kāi)始前我們先來(lái)個(gè)基礎(chǔ)知識(shí)講解吧.

![Uploading 多線程_837987.jpg . . .]

首先開(kāi)始我們先區(qū)別下進(jìn)程與線程的區(qū)別.
***
進(jìn)程:系統(tǒng)每個(gè)程序運(yùn)行都需要一個(gè)進(jìn)程,進(jìn)程間是在其專(zhuān)用且

受保護(hù)的內(nèi)存空間內(nèi)獨(dú)立的
線程:1)線程為進(jìn)程能夠正常運(yùn)作提供了條件,且每個(gè)進(jìn)程最少得一條線程.
2)所謂進(jìn)程通俗講就是我們系統(tǒng)運(yùn)行的程序,進(jìn)程的基本執(zhí)行單元為線程.

線程串行:
     在單線程中執(zhí)行任務(wù)是需要排隊(duì)的,你如果要執(zhí)行多人任務(wù),那么就只能按順序執(zhí)行這些任務(wù);就像去超市排隊(duì)結(jié)賬,你要等別  人結(jié)賬完才能輪到你

多線程

廢話(huà)不多說(shuō)先來(lái)了解下什么是多線程先
***基本概念***
多線程就是給單前的進(jìn)程(APP/程序)開(kāi)多條線程就是開(kāi)幾條水管好排水,每條水管執(zhí)行不同的Task.
***線程的并行***
所謂并行就是你像燒水的時(shí)候可以順便干點(diǎn)其它東西,大家互相互執(zhí)行不同的東西
說(shuō)白了就是你的CPU在多線線程中來(lái)回工作,就是這條線程干點(diǎn)那條線程干點(diǎn)
***多線程優(yōu)點(diǎn)與缺點(diǎn) ***
缺點(diǎn):1)開(kāi)多線程就是一個(gè)人在進(jìn)行多個(gè)任務(wù)一樣,這樣CPU開(kāi)銷(xiāo)會(huì)很大,太多線程其實(shí)會(huì)影響性能的
2)這樣程序會(huì)設(shè)計(jì)的比較復(fù)雜,在數(shù)據(jù)共享與線程(APP)間通信實(shí)現(xiàn)難度很大
3)加重內(nèi)存開(kāi)銷(xiāo)(默認(rèn)主線程是1M,子線程是512KB)

優(yōu)點(diǎn):1)目前CPU的處理效率很高都是多核多核一定程度上提高資源的利用率(內(nèi)存/CPU)
     2)提高程序執(zhí)行的效率了,就是你燒開(kāi)水去切菜一樣提高效率節(jié)省時(shí)間.

在iOS開(kāi)發(fā)中的用處

寶貝說(shuō)再好還不如來(lái)來(lái)點(diǎn)實(shí)在的對(duì)吧.
a)主線程
1.一個(gè)APP運(yùn)行后在iOS系統(tǒng)中默認(rèn)就是在主線程中運(yùn)行的我們把它稱(chēng)為"主線程"或者"UI線程"
2.刷新顯示界面,處理用戶(hù)交互事件

坑點(diǎn)!!!:1)如果是在對(duì)一些比較占用資源運(yùn)行時(shí)間較長(zhǎng)的耗時(shí)操作記住要開(kāi)子線程,要不你的APP就卡死啦
2)和用戶(hù)交互的刷新操作一定要放在主線程,要不一些執(zhí)著的用戶(hù)會(huì)以為貴公司APP垃圾辣雞就卸了.寶寶心里苦

主題幾種多線程實(shí)現(xiàn)方案

***程序員管理的生命***
pthread說(shuō)明:惡心的C語(yǔ)言API,我就不想用了,用起來(lái)好難,線程的生死還要我們程序員覺(jué)得,一不小心就崩了程序崩了知道不.
特點(diǎn):1)可用在Unix\Linux\Windows主流系統(tǒng)可以跨平臺(tái)開(kāi)發(fā)
     2)通用的API就是大家都可以用,公共廁所

NSThread特點(diǎn):1)這個(gè)東西我們偶爾使用
             2)偉大的OOP類(lèi)
             3)還是得碼農(nóng)解決生死

***系統(tǒng)自動(dòng)管理***
GCD特點(diǎn):1)為了替代NSThread等需要人工判斷生死的東西
        2)為了不浪費(fèi)多核的CPU資源
        3)還是C語(yǔ)言,使用難道大大的難

NSOperation特點(diǎn):1)OOP語(yǔ)言,系統(tǒng)會(huì)自動(dòng)管理
                2)基于GCD底層的,比GCD使用方便還新添一些簡(jiǎn)單的功能

重點(diǎn)了解OOP語(yǔ)言中的NSTHread

基本使用:創(chuàng)建的3種方式
1)自動(dòng)啟動(dòng),不能管理內(nèi)容設(shè)置
[self performSelectorInBackground:@selector(run:) withObject:@"I am 后臺(tái)線程"];
2)自動(dòng)啟動(dòng),分離出一條子線程,還是不能管理內(nèi)容設(shè)置
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分離出來(lái)的子線程"];
***推薦使用***
3)可以管理內(nèi)容設(shè)置但是需要手動(dòng)開(kāi)啟線程.
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"wendingding"];
         //啟動(dòng)線程
        [thread start];

其它一些屬性使用:
                1)屬性名稱(chēng):thread.name = @"快給我起名字";
                2)優(yōu)先級(jí)(默認(rèn)0.5):thread.threadPriority = 1.0;

線程safety:1)多線程同時(shí)操作同一個(gè)數(shù)據(jù)會(huì)發(fā)生死鎖情況,需要加互斥所,相關(guān)代碼@synchronized(self){}
2)原子性與非原子屬性(是否對(duì)setter方法加鎖), 線程同步與同步線程區(qū)別
線程同步:多個(gè)線程操作同一個(gè)數(shù)據(jù)資源提供競(jìng)爭(zhēng)的解決方案
同步線程:就是排隊(duì)串行執(zhí)行任務(wù)的線程

線程狀態(tài):[NSThread  exit]//退出當(dāng)前的線程
         [NSThread sleepForTimeInterval:2.0];
         [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
         //:線程掛了是不能復(fù)生的

線程間通信:
 -(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
    {
    //    [self download2];

        //開(kāi)啟一條子線程來(lái)下載圖片
        [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil];
    }

    -(void)downloadImage
    {
        //1.確定要下載網(wǎng)絡(luò)圖片的url地址,一個(gè)url唯一對(duì)應(yīng)著網(wǎng)絡(luò)上的一個(gè)資源
        NSURL *url = [NSURL URLWithString:@"http://www.itdecent.cn/p/e09c44c5ab12"];

        //2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進(jìn)制數(shù)據(jù)
        NSData *data = [NSData dataWithContentsOfURL:url];

        //3.把下載到本地的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成圖片
        UIImage *image = [UIImage imageWithData:data];

        //4.回到主線程刷新UI
        //4.1 第一種方式
    //    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];

        //4.2 第二種方式
    //    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

        //4.3 第三種方式
        [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
    }

計(jì)算代碼時(shí)間:
1)CFTimeInterval start = CFAbsoluteTimeGetCurrent();
        NSData *data = [NSData dataWithContentsOfURL:url];

        CFTimeInterval end = CFAbsoluteTimeGetCurrent();
        NSLog(@"操作花費(fèi)的時(shí)間為%f",end - start);
2)NSDate *start = [NSDate date];
        //2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進(jìn)制數(shù)據(jù))
        NSData *data = [NSData dataWithContentsOfURL:url];

        NSDate *end = [NSDate date];
        NSLog(@"第二步操作花費(fèi)的時(shí)間為%f",[end timeIntervalSinceDate:start]);

學(xué)習(xí)重點(diǎn) GCD

基本知識(shí):
1)同步/異步函數(shù)
2)隊(duì)列/任務(wù)理解

使用重點(diǎn):
01 異步函數(shù)+并發(fā)隊(duì)列:開(kāi)啟多條線程,并發(fā)執(zhí)行任務(wù)
02 異步函數(shù)+串行隊(duì)列:開(kāi)啟一條線程,串行執(zhí)行任務(wù)
03 同步函數(shù)+并發(fā)隊(duì)列:不開(kāi)線程,串行執(zhí)行任務(wù)
04 同步函數(shù)+串行隊(duì)列:不開(kāi)線程,串行執(zhí)行任務(wù)
05 異步函數(shù)+主隊(duì)列:不開(kāi)線程,在主線程中串行執(zhí)行任務(wù)
06 同步函數(shù)+主隊(duì)列:不開(kāi)線程,串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
07 注意同步函數(shù)和異步函數(shù)在執(zhí)行順序上面的差異

GCD中線程間通信:

  //0.獲取一個(gè)全局的隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //1.先開(kāi)啟一個(gè)線程,把下載圖片的操作放在子線程中處理
    dispatch_async(queue, ^{

       //2.下載圖片
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];

        NSLog(@"下載操作所在的線程--%@",[NSThread currentThread]);

        //3.回到主線程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
           self.imageView.image = image;
           //打印查看當(dāng)前線程
            NSLog(@"刷新UI---%@",[NSThread currentThread]);
        });

    });

GCD中其它法寶

1)柵欄函數(shù)(控制任務(wù)的執(zhí)行順序)
    dispatch_barrier_async(queue, ^{
        NSLog(@"柵欄函數(shù)");
    });

2)延遲執(zhí)行(延遲·控制在哪個(gè)線程執(zhí)行)
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"---%@",[NSThread currentThread]);
    });

3)一次性代碼(注意不能放到懶加載)
    -(void)onceToken
    {
        //整個(gè)程序運(yùn)行過(guò)程中只會(huì)執(zhí)行一次
        //onceToken用來(lái)記錄該部分的代碼是否被執(zhí)行過(guò)
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{

            NSLog(@"-----");
        });
    }

4)快速迭代(開(kāi)多個(gè)線程并發(fā)完成迭代操作)
       dispatch_apply(subpaths.count, queue, ^(size_t index) {
    });

5)隊(duì)列組(同柵欄函數(shù))
    //創(chuàng)建隊(duì)列組
    dispatch_group_t group = dispatch_group_create();
    //隊(duì)列組中的任務(wù)執(zhí)行完畢之后,執(zhí)行該函數(shù)
    dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);

6)進(jìn)入群組和離開(kāi)群組
    dispatch_group_enter(group);//執(zhí)行該函數(shù)后,后面異步執(zhí)行的block會(huì)被gruop監(jiān)聽(tīng)
    dispatch_group_leave(group);//異步block中,所有的任務(wù)都執(zhí)行完畢,最后離開(kāi)群組
    //注意:dispatch_group_enter|dispatch_group_leave必須成對(duì)使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時(shí)執(zhí)行代碼、方法又是什么? 1...
    AlanGe閱讀 1,919評(píng)論 0 17
  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專(zhuān)用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,604評(píng)論 1 33
  • 本文選譯自《Threading Programming Guide》。 導(dǎo)語(yǔ) 線程技術(shù)作為在單個(gè)應(yīng)用程序中并發(fā)執(zhí)行...
    巧巧的二表哥閱讀 2,591評(píng)論 4 24
  • 目錄 [創(chuàng)建與維護(hù)](# 1)創(chuàng)建并設(shè)置一個(gè)私有的Spec Repo創(chuàng)建PodLib創(chuàng)建lib所對(duì)應(yīng)的podspe...
    水在玩焱閱讀 8,478評(píng)論 1 10
  • 夫天地者,萬(wàn)物之逆旅。 光陰者,百代之過(guò)客。 而浮生若夢(mèng),為歡幾何? 浮生六記得名于李白這首充滿(mǎn)感傷的小序,初得此...
    追求自由的小五閱讀 412評(píng)論 1 4

友情鏈接更多精彩內(nèi)容