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

首頁(yè) > 系統(tǒng) > iOS > 正文

為什么IOS中要使用這么多的線程 有什么原因

2020-02-19 15:56:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  今天小編跟大家分享一下為什么IOS中要使用這么多的線程,有什么原因,感興趣的朋友跟小編一起來(lái)了解一下吧!

  多線程是一個(gè)比較輕量級(jí)的方法來(lái)實(shí)現(xiàn)單個(gè)應(yīng)用程序內(nèi)多個(gè)代碼執(zhí)行路徑。

  在系統(tǒng)級(jí)別內(nèi),程序并排執(zhí)行,程序分配到每個(gè)程序的執(zhí)行時(shí)間是基于該程序的所需時(shí)間和其他程序的所需時(shí)間來(lái)決定的。

  然而,在每個(gè)程序內(nèi)部,存在一個(gè)或者多個(gè)執(zhí)行線程,它同時(shí)或在一個(gè)幾乎同時(shí)發(fā)生的方式里執(zhí)行不同的任務(wù)。

  概要提示:

  iPhone中的線程應(yīng)用并不是無(wú)節(jié)制的,官方給出的資料顯示,iPhone OS下的主線程的堆棧大小是1M,第二個(gè)線程開始就是512KB,并且該值不能通過(guò)編譯器開關(guān)或線程API函數(shù)來(lái)更改,只有主線程有直接修改UI的能力

  一、線程概述

  有些程序是一條直線,起點(diǎn)到終點(diǎn)——如簡(jiǎn)單的hello world,運(yùn)行打印完,它的生命周期便結(jié)束了,像是曇花一現(xiàn)。

  有些程序是一個(gè)圓,不斷循環(huán)直到將它切斷——如操作系統(tǒng),一直運(yùn)行直到你關(guān)機(jī)。

  一個(gè)運(yùn)行著的程序就是一個(gè)進(jìn)程或者叫做一個(gè)任務(wù),一個(gè)進(jìn)程至少包含一個(gè)線程,線程就是程序的執(zhí)行流。

  Mac和IOS中的程序啟動(dòng),創(chuàng)建好一個(gè)進(jìn)程的同時(shí),一個(gè)線程便開始運(yùn)作,這個(gè)線程叫做主線程。主線成在程序中的位置和其他線程不同,它是其他線程最終的父線程,且所有的界面的顯示操作即AppKit或UIKit的操作必須在主線程進(jìn)行。

  系統(tǒng)中每一個(gè)進(jìn)程都有自己獨(dú)立的虛擬內(nèi)存空間,而同一個(gè)進(jìn)程中的多個(gè)線程則公用進(jìn)程的內(nèi)存空間。

  每創(chuàng)建一個(gè)新的進(jìn)成,都需要一些內(nèi)存(如每個(gè)線程有自己的stack空間)和消耗一定的CPU時(shí)間。

  當(dāng)多個(gè)進(jìn)成對(duì)同一個(gè)資源出現(xiàn)爭(zhēng)奪的時(shí)候需要注意線程安全問(wèn)題

  創(chuàng)建線程

  創(chuàng)建一個(gè)新的線程就是給進(jìn)程增加一個(gè)執(zhí)行流,所以新建一個(gè)線程需要提供一個(gè)函數(shù)或者方法作為線程的進(jìn)口。

  1.使用NSThread

  NSThread提供了創(chuàng)建線程的路徑,還可以提供了監(jiān)測(cè)當(dāng)前線程是否是主線程的方法使用NSThread創(chuàng)建一個(gè)新的線程有兩種方式:

  1.創(chuàng)建一個(gè)NSThread的對(duì)象,調(diào)用Start方法——使用一個(gè)目標(biāo)對(duì)象的方法初始化一個(gè)NSThread對(duì)象,或者創(chuàng)建一個(gè)繼承自NSThread的子類,實(shí)現(xiàn)起main方法?,然后在直接創(chuàng)建這個(gè)子類的對(duì)象。

  2.使用detachNewThreadSelector:toTarget:withObject:這個(gè)類方法創(chuàng)建一個(gè)子線程,這個(gè)比較直接,直接使用目標(biāo)對(duì)象的方法作為線程啟動(dòng)入口

  2.使用NSObject

  使用NSObject直接就加入了對(duì)多線程的支持,允許對(duì)象的某個(gè)方法在后臺(tái)運(yùn)行。

  [my0bj performSelectorInBackground:@selector(doSomething) withObject:nil];

  3.POSIX Thread

  由于Mac和IOS都是基于Darwin系統(tǒng),Darwin系統(tǒng)的UNX內(nèi)核,是基于mach和BSD的,繼承了BSD的POSIX接口,所以可以直接使用POSIX線程的相關(guān)接口開實(shí)現(xiàn)線程

  創(chuàng)建線程的接口為 pthread_create, 當(dāng)然在創(chuàng)建線程之前可以創(chuàng)建好相關(guān)線程的屬性

  ——————————————————————————————————————

  NSOperation&NSOperationQueue

  很多時(shí)候我們使用多線程,需要控制線程的并發(fā)數(shù),畢竟線程也是需要消耗系統(tǒng)資源的,當(dāng)程序中同時(shí)運(yùn)行的線程過(guò)多時(shí),系統(tǒng)必然變慢,所以很多時(shí)候我們會(huì)控制同時(shí)運(yùn)行線程的數(shù)目

  NSOperation可以封裝我們的操作,然后將創(chuàng)建好的NSOperation對(duì)象放到NSOperationQueue隊(duì)列中,OperationQueue便開始啟動(dòng)新的線程去執(zhí)行隊(duì)列中的操作,OperationQueue的并發(fā)數(shù)時(shí)可以通過(guò)如下方式進(jìn)行設(shè)置的:

  - (void)setMaxConcurrentOperationCount:(NSInteger)count

  GCD時(shí)Grand central Dispatch的縮寫,是一系列BSD層面的接口。在mac10.6和IOS4.0以后才引入的且現(xiàn)在NSOperation和NSOperationQueue的多線程的實(shí)現(xiàn)就是基于GCD的。目前這個(gè)特性也被移植到 FreeBSD上了,可以查看libdispatch這個(gè)開源項(xiàng)目。

  dispatch_queue_t imageDownloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  當(dāng)然,GCD除了處理多線程外還有很多非常好的功能,其建立在強(qiáng)大的kqueue之上,效率也能夠得到保障。

  前言

  在多線程簡(jiǎn)介中,我已經(jīng)說(shuō)明過(guò)了,為了提高界面的流暢度以及用戶體驗(yàn)。我們務(wù)必要把耗時(shí)的操作放到別的線程中去執(zhí)行,千萬(wàn)不要阻塞主線程。

  下面小編給大家?guī)?lái)三種ios多線程編程方法:

  NSThread

  Grand Centeral Dispatch(GCD)

  NSOperation和NSOperationQueue

  1.NSThread

  這是最輕量級(jí)的多線程的方法,使用起來(lái)最直觀的多線程編程方法。但是因?yàn)樾枰约汗芾砭€程的生命周期,線程同步。經(jīng)常使用NSThread進(jìn)行調(diào)試,在實(shí)際項(xiàng)目中不推薦使用。

  //獲取當(dāng)前線程

  NSThread *current = [NSThread currentThread];

  //獲取主線程

  NSThread *main = [NSThread mainThread];

  NSLog(@"當(dāng)前線程 --- %@",current);

  NSLog(@"主線程 --- %@",main);

  控制臺(tái)輸出結(jié)果:

  2015-11-22 22:30:29.572 多線程demo[1289:2925847] 當(dāng)前線程 --- {number = 1, name = main}

  2015-11-22 22:30:29.572 多線程demo[1289:2925847] 主線程 --- {number = 1, name = main}

  從結(jié)果我們看出當(dāng)前的線程就是主線程, number 相當(dāng)于線程的id, name 是線程的名稱,主線程的number就是1

  阻塞線程:

  //阻塞線程3秒

  [NSThread sleepForTimeInterval:3];

  [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];

  2.GCD(Grand Central Dispatch)

  GCD是基于C語(yǔ)言底層API實(shí)現(xiàn)的一套多線程并發(fā)機(jī)制,非常的靈活方便,在實(shí)際的開發(fā)中使用很廣泛。

  簡(jiǎn)單來(lái)說(shuō)CGD就是把 操作 放在 隊(duì)列 中去執(zhí)行。

  你只需定義好操作和隊(duì)列就可以了,不需要直接控制線程的創(chuàng)建和銷毀,線程的生命周期由隊(duì)列來(lái)管理。

  隊(duì)列:負(fù)責(zé)操作的調(diào)度和執(zhí)行,有先進(jìn)先出(FIFO)的特點(diǎn)。也就是說(shuō)先加入隊(duì)列的操作先執(zhí)行,后加入的后執(zhí)行。

  隊(duì)列有兩種:

  串行隊(duì)列:

  隊(duì)列中的操作只會(huì)按順序執(zhí)行,你可以想象成單窗口排隊(duì)。

  并行隊(duì)列:

  隊(duì)列中的操作可能會(huì)并發(fā)執(zhí)行,這取決與操作的類型,你可以想象成多窗口排隊(duì)。

  //創(chuàng)建串行隊(duì)列

  dispatch_queue_t q = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);

  //創(chuàng)建并行隊(duì)列

  dispatch_queue_t q = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

  my_serial_queue和my_concurrent_queue是隊(duì)列的名字標(biāo)簽,為了與其他的隊(duì)列區(qū)分,在一個(gè)項(xiàng)目里面必須是唯一的。

  DISPATCH_QUEUE_SERIAL表示串行隊(duì)列

  DISPATCH_QUEUE_CONCURRENT表示并行隊(duì)列

  操作同樣也分兩種類型:

  同步操作:只會(huì)按順序執(zhí)行,執(zhí)行順序是確定的。

  異步操作:在串行隊(duì)列中執(zhí)行順序確定,在并行隊(duì)列中執(zhí)行順序不確定

  使用block來(lái)定義操作要執(zhí)行的代碼,q是已經(jīng)定義好的,操作要加入的隊(duì)列

  //定義同步操作

  dispatch_sync(q, ^{

  //要執(zhí)行的代碼

  });

  //定義異步操作

  dispatch_async(q, ^{

  //要執(zhí)行的代碼

  });

  下面我們看一下同步,異步操作加入到串行和并行隊(duì)列里面,執(zhí)行的順序和特點(diǎn):1.同步操作不管加入到何種隊(duì)列,只會(huì)在主線程按順序執(zhí)行

  dispatch_queue_t q_serial = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);

  dispatch_queue_t q_concurrent = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

  for (int i = 0; i

  下面是控制臺(tái)輸出結(jié)果:

  2015-11-23 00:40:36.862 01.GCD演練[1952:3613752] 串行隊(duì)列里的同步任務(wù) {number = 1, name = main} 0

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊(duì)列里的同步任務(wù) {number = 1, name = main} 1

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊(duì)列里的同步任務(wù) {number = 1, name = main} 2

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊(duì)列里的同步任務(wù) {number = 1, name = main} 3

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊(duì)列里的同步任務(wù) {number = 1, name = main} 4

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 并行隊(duì)列里的同步任務(wù) {number = 1, name = main} 0

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 并行隊(duì)列里的同步任務(wù) {number = 1, name = main} 1

  2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 并行隊(duì)列里的同步任務(wù) {number = 1, name = main} 2

  2015-11-23 00:40:36.864 01.GCD演練[1952:3613752] 并行隊(duì)列里的同步任務(wù) {number = 1, name = main} 3

  2015-11-23 00:40:36.864 01.GCD演練[1952:3613752] 并行隊(duì)列里的同步任務(wù) {number = 1, name = main} 4

  2.異步操作只在非主線程的線程執(zhí)行,在串行隊(duì)列中異步操作會(huì)在新建的線程中按順序執(zhí)行。

  dispatch_queue_t q_serial = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);

  for(int i = 0; i

  因?yàn)槭钱惒讲僮鳎詴?huì)新建一個(gè)線程。又因?yàn)榧尤氲酱嘘?duì)列中,所以所有的操作只會(huì)按順序執(zhí)行。

  2015-11-23 01:03:22.372 01.GCD演練[2081:3627139] 串行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 0

  2015-11-23 01:03:23.373 01.GCD演練[2081:3627139] 串行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 1

  2015-11-23 01:03:24.374 01.GCD演練[2081:3627139] 串行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 2

  2015-11-23 01:03:25.375 01.GCD演練[2081:3627139] 串行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 3

  2015-11-23 01:03:26.376 01.GCD演練[2081:3627139] 串行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 4

  3.異步操作,并行隊(duì)列

  dispatch_queue_t q_concurrent = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

  for(int i = 0; i

  理論上并行隊(duì)列會(huì)給每一個(gè)異步操作新建線程,然后讓所有的任務(wù)并發(fā)執(zhí)行。但是實(shí)際上系統(tǒng)能創(chuàng)建的線程數(shù)量是有限的,當(dāng)創(chuàng)建的線程達(dá)到最大線程數(shù)以后,后面的異步操作就需要等待前面的操作執(zhí)行完畢才能得到執(zhí)行。哪個(gè)線程操作執(zhí)行完畢,就把等待的異步任務(wù)安排到哪個(gè)線程。直到所有的操作執(zhí)行完畢。你可以把上述代碼的循環(huán)次數(shù)改成5000就可以觀察到此現(xiàn)象。

  2015-11-23 01:14:15.282 01.GCD演練[2165:3634728] 并行隊(duì)列 -- 異步任務(wù) {number = 4, name = (null)} 3

  2015-11-23 01:14:15.282 01.GCD演練[2165:3634724] 并行隊(duì)列 -- 異步任務(wù) {number = 3, name = (null)} 0

  2015-11-23 01:14:15.282 01.GCD演練[2165:3634726] 并行隊(duì)列 -- 異步任務(wù) {number = 5, name = (null)} 2

  2015-11-23 01:14:15.282 01.GCD演練[2165:3634725] 并行隊(duì)列 -- 異步任務(wù) {number = 2, name = (null)} 1

  2015-11-23 01:14:15.285 01.GCD演練[2165:3634729] 并行隊(duì)列 -- 異步任務(wù) {number = 6, name = (null)} 4

  3.NSOperation & NSOperationQueue

  雖然GCD的功能已經(jīng)很強(qiáng)大了,但是它使用的API依然是C語(yǔ)言的。在某些時(shí)候,在面向?qū)ο蟮膐bjective-c中使用起來(lái)非常的不方便和不安全。

  所以蘋果公司把GCD中的操作抽象成NSOperation對(duì)象,把隊(duì)列抽象成NSOperationQueue對(duì)象。

  抽象為NSOperation & NSOperationQueue以后的好處有一下幾點(diǎn):

  代碼風(fēng)格統(tǒng)一了,我們不用在面向?qū)ο蟮膐bjective-C中寫面對(duì)過(guò)程的C語(yǔ)言代碼了。

  我們知道在GCD中操作的執(zhí)行代碼都是寫在匿名的block里面,那么我們很難做到給操作設(shè)置依賴關(guān)系以及取消操作。這些功能都已經(jīng)封裝到NSOperation對(duì)象里面了。^-^

  NSOperationQueue對(duì)象比GCD中隊(duì)列更加的強(qiáng)大和靈活,比如:設(shè)置并發(fā)操作數(shù)量,取消隊(duì)列中所有操作。

  NSOperation分為NSInvocationOperation和NSBlockOperation

  NSInvocationOperation的使用

  //首先定義一個(gè)NSOperationQueue對(duì)象

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

  NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@"這里可以穿參數(shù)"];

  [queue addOperation:op];//把操作加入隊(duì)列中即開始執(zhí)行

  - (void)operationAction:(id)obj

  {

  NSLog(@"%@ - obj : %@", [NSThread currentThread], obj);

  }

  輸出為:

  2015-11-23 02:55:19.067 多線程demo[2604:3686934] {number = 2, name = (null)} - obj : 這里可以穿參數(shù)

  NSBlockOperation的使用

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

  NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

  [self operationAction:@"這是NSBlockOperation"];

  }];

  [queue addOperation:op];

  輸出為:

  2015-11-23 02:56:11.812 多線程demo[2617:3687872] {number = 2, name = (null)} - obj : 這是NSBlockOperation

  設(shè)置依賴關(guān)系(執(zhí)行順序)

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

  NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@"op1"];

  NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@"op2"];

  //op2在op1之后執(zhí)行

  [op2 addDependency:op1];//這里需要注意,一定要在addOperation之前設(shè)置依賴關(guān)系

  [queue addOperation:op1];

  [queue addOperation:op2];

  輸出為:

  2015-11-23 02:57:40.283 多線程demo[2661:3689737] {number = 2, name = (null)} - obj : op1

  2015-11-23 02:57:40.284 多線程demo[2661:3689737] {number = 2, name = (null)} - obj : op2

  沒(méi)有設(shè)置依賴關(guān)系的輸出:

  2015-11-23 03:00:45.939 多線程demo[2709:3692307] {number = 2, name = (null)} - obj : op2

  2015-11-23 03:00:45.939 多線程demo[2709:3692308] {number = 3, name = (null)} - obj : op1

  到這里你應(yīng)該發(fā)現(xiàn)了,在NSOperation & NSOperationQueue中,我們不需要再像GCD那樣定義操作的類型和隊(duì)列的類型和控制操作的執(zhí)行順序了,你只需要直接設(shè)定操作的執(zhí)行順序就可以了。

  以上所述就是為什么IOS中要使用這么多的線程,有什么原因的介紹,希望大家能夠喜歡,更多內(nèi)容請(qǐng)繼續(xù)關(guān)注武林技術(shù)頻道網(wǎng)站!

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 无为县| 罗甸县| 东乡| 垦利县| 井研县| 汝南县| 建宁县| 南木林县| 江永县| 汽车| 龙井市| 关岭| 康定县| 余干县| 师宗县| 栾城县| 台北市| 宜章县| 邳州市| 玉林市| 永嘉县| 瓮安县| 阿拉善盟| 巴塘县| 永昌县| 都兰县| 扬中市| 东兰县| 诸城市| 静安区| 甘南县| 紫云| 临武县| 安平县| 呼伦贝尔市| 盐源县| 建水县| 达州市| 保亭| 图木舒克市| 南召县|