茶余飯后的多線(xiàn)程

茶余飯后的多線(xiàn)程

故事是這樣的:

艷:戴戴,我最近要面試抹锄,但是我都不知道會(huì)面試什么東西逆瑞!

戴:多線(xiàn)程荠藤,內(nèi)存,源碼获高,runtime等哈肖!

艷不爽:我也知道是這些,可是具體面試啥呢念秧?

戴:比如多線(xiàn)程淤井!額...

沉思片刻...

額 ....

艷:切。

戴:額... 多線(xiàn)程(英語(yǔ):multithreading)摊趾,是指從軟件或者硬件上實(shí)現(xiàn)多個(gè)線(xiàn)程并發(fā)執(zhí)行的技術(shù)币狠。具有多線(xiàn)程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多于一個(gè)線(xiàn)程,進(jìn)而提升整體處理性能砾层。

艷:能不能具體點(diǎn)漩绵!

戴:這樣!假如我現(xiàn)在想做一個(gè)下載的功能肛炮,但是呢止吐,我肯定不能在主線(xiàn)程上下載對(duì)不對(duì)?

嗯...

那我就需要開(kāi)個(gè)子線(xiàn)程

異步下載

dispatch_queue_t queue = dispatch_queue_create("1", nil);
dispatch_async(queue, ^{
    NSLog(@"download...");
});

就像這樣侨糟,我創(chuàng)建個(gè)線(xiàn)程讓他異步執(zhí)行就好了碍扔。

艷:但是這樣下載完了,主線(xiàn)程根本不知道粟害!

戴:可以這樣

異步下載之后回調(diào)主線(xiàn)程

dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
    //這里假設(shè)sleep是在download
    sleep(rand()%10);
    NSLog(@"download...");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"dowload complete!");
    });
});

這里有一個(gè)要注意一下哈蕴忆!

  • DISPATCH_QUEUE_CONCURRENT:并行隊(duì)列,以先進(jìn)先出的方式悲幅,并發(fā)調(diào)度隊(duì)列中的任務(wù)執(zhí)行
    如果當(dāng)前調(diào)度的任務(wù)是同步執(zhí)行的套鹅,會(huì)等待任務(wù)執(zhí)行完成后,再調(diào)度后續(xù)的任務(wù)
    如果當(dāng)前調(diào)度的任務(wù)是異步執(zhí)行的汰具,同時(shí)底層線(xiàn)程池有可用的線(xiàn)程資源卓鹿,會(huì)再新的線(xiàn)程調(diào)度后續(xù)任務(wù)的執(zhí)行

  • DISPATCH_QUEUE_SERIAL:串行隊(duì)列,永遠(yuǎn)是任務(wù)一個(gè)一個(gè)的執(zhí)行

艷:那我明白了留荔,如果我想要同時(shí)下載5個(gè)文件我就可以這樣

創(chuàng)建并行隊(duì)列吟孙,多任務(wù)同步執(zhí)行

for (NSInteger i = 0 ; i < 5; i ++ ) {
    dispatch_queue_t dqueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(dqueue, ^{
        //這里假設(shè)sleep是在download
        sleep(rand()%10);
        NSLog(@"dowload %ld",i);
    });
}

戴:沒(méi)錯(cuò)的,可是如果有100個(gè)聚蝶,1000個(gè)文件要下載呢杰妓?

艷:那我就for循環(huán)100次,1000...好像不大對(duì)哦碘勉?

戴:因?yàn)樵O(shè)備性能的問(wèn)題巷挥,100,1000循環(huán)創(chuàng)建,這種方式明顯不可取验靡,那也就是我們需要讓他每次并行的數(shù)量有一個(gè)控制倍宾。這時(shí)候我們會(huì)聯(lián)想到一個(gè)名詞叫做信號(hào)量雏节!

信號(hào)量:信號(hào)量(Semaphore),有時(shí)被稱(chēng)為信號(hào)燈高职,是在多線(xiàn)程環(huán)境下使用的一種設(shè)施钩乍,是可以用來(lái)保證兩個(gè)或多個(gè)關(guān)鍵代碼段不被并發(fā)調(diào)用。

通過(guò)信號(hào)量控制怔锌,同時(shí)只有五個(gè)任務(wù)在下載

dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
dispatch_queue_t ddqueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);

for (NSInteger i = 0; i < 100; i ++) {
    dispatch_async(ddqueue, ^{
        sleep(rand()%10);
        NSLog(@"dowload %ld",i);
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }
}

這里我解釋一下這個(gè)信號(hào)量怎么運(yùn)作的寥粹。

  • dispatch_semaphore_create:創(chuàng)建信號(hào)量,并且傳入的參數(shù)是個(gè)long類(lèi)型产禾,意義就是可以同時(shí)存在多少資源數(shù)排作,這里可以理解為線(xiàn)程
  • dispatch_semaphore_signal:發(fā)送信號(hào)牵啦,會(huì)使當(dāng)前信號(hào)量 +1
  • dispatch_semaphore_wait:減低信號(hào)亚情,如果當(dāng)前信號(hào)量大于1,會(huì)使當(dāng)前信號(hào)量-1,如果等于0 進(jìn)入等待哈雏。后面跟的時(shí)間就是等待的時(shí)長(zhǎng)了楞件。

那么上面的代碼意思就是我同時(shí)開(kāi)始下載的任務(wù)只有五個(gè),有一個(gè)下載完就會(huì)進(jìn)入下一個(gè)了裳瘪。

艷:嗯...我如果想給任務(wù)排個(gè)序土浸,就是知道完成的順序怎么辦呢?

戴:這就涉及到多線(xiàn)程里面比較常用的鎖了彭羹。

多線(xiàn)程中的鎖

NSLock *lock = [[NSLock alloc] init];
__block NSInteger index = 0;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
dispatch_queue_t ddqueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);

for (NSInteger i = 0; i < 100; i ++) {
    dispatch_async(ddqueue, ^{
        sleep(rand()%10);
        [lock lock];
        NSLog(@"the index of %ld: %ld",index,i);
        index ++;
        [lock unlock];
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

這樣就會(huì)有順序了黄伊,對(duì)index進(jìn)行讀寫(xiě)的時(shí)候進(jìn)行加鎖,防止index被其他線(xiàn)程給改了派殷。

艷:那么如果有些任務(wù)要是失敗了还最,我是不是應(yīng)該給他重新下,這個(gè)怎么做毡惜?

戴:有兩種方案:

  • 方案1:如果不成功就重復(fù)調(diào)用當(dāng)前線(xiàn)程拓轻,也就是如果不成功就重復(fù)跑下載線(xiàn)程,讓他占著資源经伙。
  • 方案2:如果不成功扶叉,就把當(dāng)前任務(wù)丟到任務(wù)尾部,等其他任務(wù)下載完了之后再去執(zhí)行這個(gè)任務(wù)帕膜。

大多下載工具的實(shí)現(xiàn)是 方案1 + 方案2 的結(jié)合枣氧。

為了簡(jiǎn)單,我就只展示給你看下方案2哈垮刹,因?yàn)榉桨敢淮锿蹋嗑€(xiàn)程關(guān)系不大。

這里我用一個(gè)array來(lái)代表一些下載任務(wù)吧危纫。

多任務(wù)下載的下載失敗處理

NSInteger totalCount = 100;
NSLock *lock = [[NSLock alloc] init];
NSMutableArray *needDownloadarray = [[NSMutableArray alloc] init];
for (int i =0 ; i < totalCount; i ++) {
    [array addObject:@1];
}
__block NSInteger index = 0;
__block NSInteger completeCount = 0;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_queue_t ddqueue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);

BOOL stop = false;
while (completeCount != totalCount && !stop) {
    if (needDownloadarray.count > 0) {
        [lock lock];
        [needDownloadarray removeObject:[needDowanloadarray firstObject]];
        [lock unlock];
        dispatch_async(ddqueue, ^{
            NSInteger randomcount = rand()%10;
            sleep((unsigned int)randomcount / 5);
            [lock lock];
            index ++;
            if (randomcount > 8) {
                [needDownloadarray addObject:@1];
                NSLog(@"the index of %ld , download failed",index);
            } else {
                completeCount ++ ;
                NSLog(@"the index of %ld , complete is %ld",index,completeCount);
            }

            [lock unlock];
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }
}
NSLog(@"download completed!");

如果隨機(jī)數(shù)大于8宗挥,我們假設(shè)他失敗吧乌庶!哈哈!

  • 如果下載失敗契耿,就把任務(wù)丟到needDownloadarray最后面

戴:這下明白了不瞒大!

艷:嗯

戴:其實(shí)嘛,這種多個(gè)文件下載搪桂,直接打個(gè)包下載就好了透敌,下下來(lái)解壓一下就完了,文件太大給他搞個(gè)斷點(diǎn)續(xù)傳踢械,就美滋滋了酗电。

艷:那你不早說(shuō)!

戴:你不是想知道多線(xiàn)程么内列?

艷:切撵术!那你跟我說(shuō)說(shuō)斷點(diǎn)續(xù)傳!

戴:我地乖乖话瞧,不早了嫩与,洗洗睡吧!明天...明天...

注意

  • 信號(hào)量里面的wait,signal要配對(duì)使用交排,不然也會(huì)造成死鎖划滋。
  • 多線(xiàn)程訪問(wèn)同一塊內(nèi)存的時(shí)候,盡量加鎖
  • 加鎖實(shí)際上會(huì)增加調(diào)度消耗埃篓,并不是鎖越多越好处坪,怎么把鎖的調(diào)度變得合理是一門(mén)課題。
  • 還有很多注意大家自己發(fā)掘
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末架专,一起剝皮案震驚了整個(gè)濱河市同窘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胶征,老刑警劉巖塞椎,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異睛低,居然都是意外死亡案狠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)钱雷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骂铁,“玉大人,你說(shuō)我怎么就攤上這事罩抗±郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵套蒂,是天一觀的道長(zhǎng)钞支。 經(jīng)常有香客問(wèn)我茫蛹,道長(zhǎng),這世上最難降的妖魔是什么烁挟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任婴洼,我火速辦了婚禮,結(jié)果婚禮上撼嗓,老公的妹妹穿的比我還像新娘柬采。我一直安慰自己,他們只是感情好且警,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布粉捻。 她就那樣靜靜地躺著,像睡著了一般斑芜。 火紅的嫁衣襯著肌膚如雪肩刃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天押搪,我揣著相機(jī)與錄音树酪,去河邊找鬼浅碾。 笑死大州,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垂谢。 我是一名探鬼主播厦画,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼滥朱!你這毒婦竟也來(lái)了根暑?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤徙邻,失蹤者是張志新(化名)和其女友劉穎排嫌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體缰犁,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淳地,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帅容。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颇象。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡房待,死狀恐怖抄邀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情傅物,我是刑警寧澤麦乞,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布蕴茴,位于F島的核電站劝评,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏倦淀。R本人自食惡果不足惜付翁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晃听。 院中可真熱鬧百侧,春花似錦、人聲如沸能扒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)初斑。三九已至辛润,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間见秤,已是汗流浹背砂竖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹃答,地道東北人乎澄。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像测摔,于是被迫代替她去往敵國(guó)和親置济。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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

  • iOS多線(xiàn)程編程 基本知識(shí) 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序锋八,就是一段程序的執(zhí)...
    陵無(wú)山閱讀 6,028評(píng)論 1 14
  • 本文用來(lái)介紹 iOS 多線(xiàn)程中 GCD 的相關(guān)知識(shí)以及使用方法浙于。這大概是史上最詳細(xì)、清晰的關(guān)于 GCD 的詳細(xì)講...
    花花世界的孤獨(dú)行者閱讀 498評(píng)論 0 1
  • 這顆最?lèi)?ài)。人生坎坷紊服,失雙親檀轨,工作受挫,原本以為活著沒(méi)有意義围苫。成親了裤园,有了奔頭,有了后代剂府,存了希望拧揽。但婚變毀了一切,...
    禿瓜閱讀 134評(píng)論 0 0
  • 我在家門(mén)口的北山訪客中心做義工三年左右了。第一次到這個(gè)地方還是我和先生一起轉(zhuǎn)山時(shí)不知不覺(jué)拐進(jìn)去的淤袜,我們都驚訝于它的...
    鳳城物語(yǔ)閱讀 262評(píng)論 0 0
  • 多少相思 吹不熄多年奢侈的孤獨(dú) 一種執(zhí)念 越長(zhǎng)大越不舍得輕易撒手 記憶中散碎的煙花 毫無(wú)預(yù)謀的在 甜蜜的歲月 清澈...
    風(fēng)沙蝕骨閱讀 1,550評(píng)論 96 206