你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 在IOS中為什麼運用多線程及多線程完成的三種辦法

在IOS中為什麼運用多線程及多線程完成的三種辦法

編輯:IOS開發綜合

多線程是一個比擬輕量級的辦法來完成單個使用順序內多個代碼執行途徑。

在零碎級別內,順序並排執行,順序分配到每個順序的執行時間是基於該順序的所需時間和其他順序的所需時間來決議的。

但是,在每個順序外部,存在一個或許多個執行線程,它同時或在一個簡直同時發作的方式裡執行不同的義務。

概要提示:

iPhone中的線程使用並不是無節制的,官方給出的材料顯示,iPhone OS下的主線程的堆棧大小是1M,第二個線程開端就是512KB,並且該值不能經過編譯器開關或線程API函數來更改,只要主線程有直接修正UI的才能

一、線程概述

有些順序是一條直線,終點到起點——如復雜的hello world,運轉打印完,它的生命周期便完畢了,像是稍縱即逝。

有些順序是一個圓,不時循環直到將它切斷——如操作零碎,不斷運轉直到你關機。

一個運轉著的順序就是一個進程或許叫做一個義務,一個進程至多包括一個線程,線程就是順序的執行流。

Mac和IOS中的順序啟動,創立好一個進程的同時,一個線程便開端運作,這個線程叫做主線程。主線成在順序中的地位和其他線程不同,它是其他線程最終的父線程,且一切的界面的顯示操作即AppKit或UIKit的操作必需在主線程停止。

零碎中每一個進程都有自己獨立的虛擬內存空間,而同一個進程中的多個線程則公用進程的內存空間。

每創立一個新的進成,都需求一些內存(如每個線程有自己的stack空間)和耗費一定的CPU時間。

當多個進成對同一個資源呈現搶奪的時分需求留意線程平安問題

創立線程

創立一個新的線程就是給進程添加一個執行流,所以新建一個線程需求提供一個函數或許辦法作為線程的出口。

1.運用NSThread

NSThread提供了創立線程的途徑,還可以提供了監測以後線程能否是主線程的辦法運用NSThread創立一個新的線程有兩種方式:

1.創立一個NSThread的對象,調用Start辦法——運用一個目的對象的辦法初始化一個NSThread對象,或許創立一個承繼自NSThread的子類,完成起main辦法?,然後在直接創立這個子類的對象。

2.運用detachNewThreadSelector:toTarget:withObject:這個類辦法創立一個子線程,這個比擬直接,直接運用目的對象的辦法作為線程啟動入口

2.運用NSObject

運用NSObject直接就參加了對多線程的支持,允許對象的某個辦法在後台運轉。

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

3.POSIX Thread

由於Mac和IOS都是基於DarWin零碎,DarWin零碎的UNX內核,是基於mach和BSD的,承繼了BSD的POSIX接口,所以可以直接運用POSIX線程的相關接口開完成線程
創立線程的接口為 pthread_create, 當然在創立線程之前可以創立好相關線程的屬性

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

NSOperation&NSOperationQueue

很多時分我們運用多線程,需求控制線程的並發數,畢竟線程也是需求耗費零碎資源的,當順序中同時運轉的線程過多時,零碎必定變慢,所以很多時分我們會控制同時運轉線程的數目
NSOperation可以封裝我們的操作,然後將創立好的NSOperation對象放到NSOperationQueue隊列中,OperationQueue便開端啟動新的線程去執行隊列中的操作,OperationQueue的並發數時可以經過如下方式停止設置的:

- (void)setMaxConcurrentOperationCount:(NSInteger)count

GCD時Grand central Dispatch的縮寫,是一系列BSD層面的接口。在mac10.6和IOS4.0當前才引入的且如今NSOperation和NSOperationQueue的多線程的完成就是基於GCD的。目前這個特性也被移植到 FreeBSD上了,可以檢查libdispatch這個開源項目。

dispatch_queue_t imageDownloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

當然,GCD除了處置多線程外還有很多十分好的功用,其樹立在弱小的kqueue之上,效率也可以失掉保證。

前言

在多線程簡介中,我曾經闡明過了,為了進步界面的流利度以及用戶體驗。我們務必要把耗時的操作放到別的線程中去執行,千萬不要阻塞主線程。

上面本站給大家帶來三種ios多線程編程辦法:

NSThread
Grand Centeral Dispatch(GCD)
NSOperation和NSOperationQueue

1.NSThread

這是最輕量級的多線程的辦法,運用起來最直觀的多線程編程辦法。但是由於需求自己管理線程的生命周期,線程同步。常常運用NSThread停止調試,在實踐項目中不引薦運用。

?

1

2

3

4

5

6

//獲取以後線程

NSThread *current = [NSThread currentThread];

//獲取主線程

NSThread *main = [NSThread mainThread];

NSLog(@"以後線程 --- %@",current);

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

控制台輸入後果:

2015-11-22 22:30:29.572 多線程demo[1289:2925847] 以後線程 --- <NSThread: 0x7fc0e1401dc0>{number = 1, name = main}
2015-11-22 22:30:29.572 多線程demo[1289:2925847] 主線程 --- <NSThread: 0x7fc0e1401dc0>{number = 1, name = main}

從後果我們看出以後的線程就是主線程, number 相當於線程的id, name 是線程的稱號,主線程的number就是1

阻塞線程:

?

1

2

3

//阻塞線程3秒

[NSThread sleepForTimeInterval:3];

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

2.GCD(Grand Central Dispatch)

GCD是基於C言語底層API完成的一套多線程並發機制,十分的靈敏方便,在實踐的開發中運用很普遍。

復雜來說CGD就是把 操作 放在 隊列 中去執行。

你只需定義好操作和隊列就可以了,不需求直接控制線程的創立和銷毀,線程的生命周期由隊列來管理。

隊列:擔任操作的調度和執行,有先進先出(FIFO)的特點。也就是說先參加隊列的操作先執行,後參加的後執行。

隊列有兩種:

串行隊列:

隊列中的操作只會按順序執行,你可以想象成單窗口排隊。

在IOS中為什麼使用多線程及多線程實現的三種方法

並行隊列:

隊列中的操作能夠會並發執行,這取決與操作的類型,你可以想象成多窗口排隊。

在IOS中為什麼使用多線程及多線程實現的三種方法

?

1

2

3

4

//創立串行隊列

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

//創立並行隊列

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

my_serial_queue和my_concurrent_queue是隊列的名字標簽,為了與其他的隊列區分,在一個項目外面必需是獨一的。

DISPATCH_QUEUE_SERIAL表示串行隊列

DISPATCH_QUEUE_CONCURRENT表示並行隊列

操作異樣也分兩品種型:

同步操作:只會按順序執行,執行順序是確定的。

異步操作:在串行隊列中執行順序確定,在並行隊列中執行順序不確定

運用block來定義操作要執行的代碼,q是曾經定義好的,操作要參加的隊列

?

1

2

3

4

5

6

7

8

//定義同步操作

dispatch_sync(q, ^{

//要執行的代碼

});

//定義異步操作

dispatch_async(q, ^{

//要執行的代碼

});

上面我們看一下同步,異步操作參加到串行和並行隊列外面,執行的順序和特點:


(留意: 這裡有一點要闡明,那就是隊列是擔任線程的,可以以為是線程池,擔任需求開多少條線程,怎樣開,線程的生命周期;

同步異步是擔任開不開線程的問題,同步並不是保證義務一定在主線程執行,這個很多人都說錯了,詳細block中的義務在那條線程執行,

需求處決於上下文的。

同步異步的區別是: 有沒有創立新的線程,同步不會創立新的線程去執行義務,會阻塞以後的線程,異步會創新新的線程執行義務,不會阻塞以後的

線程;(舉個列子:假設以後線程number是2,那麼同步義務就會阻塞線程2,等到block執行終了才會去執行number2中剩下的義務;假如是異步就會創立一條新的線程能夠是number3去執行block中的義務,而不會阻塞number2的執行)

串行並行的區別是:串行隊列外面的義務都是有序執行的FIFO形式,並行隊列類似於多個窗口排隊,不能保證義務一定有序。

GCD 用的不好能夠招致死碩的問題,在我的下一篇博客中有闡明。

)

1.同步操作不論參加到何種隊列

?

1

2

3

4

5

6

7

8

9

10

11

12

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(inti = 0; i < 5; ++i) {

dispatch_sync(q_serial, ^{

NSLog(@"串行隊列裡的同步義務 %@ %d", [NSThread currentThread], i);

});

}

for(inti = 0; i < 5; ++i) {

dispatch_sync(q_concurrent, ^{

NSLog(@"並行隊列裡的同步義務 %@ %d", [NSThread currentThread], i);

});

}

上面是控制台輸入後果:

2015-11-23 00:40:36.862 01.GCD演練[1952:3613752] 串行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 0
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 1
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 2
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 3
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 串行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 4
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 並行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 0
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 並行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 1
2015-11-23 00:40:36.863 01.GCD演練[1952:3613752] 並行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 2
2015-11-23 00:40:36.864 01.GCD演練[1952:3613752] 並行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 3
2015-11-23 00:40:36.864 01.GCD演練[1952:3613752] 並行隊列裡的同步義務 <NSThread: 0x7ff833505450>{number = 1, name = main} 4

2.異步操作只在非主線程的線程執行,在串行隊列中異步操作會在新建的線程中按順序執行。

?

1

2

3

4

5

6

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

for(inti = 0; i < 5; ++i){

dispatch_async(q_serial, ^{

NSLog(@"串行隊列 -- 異步義務 %@ %d", [NSThread currentThread], i);

});

}

由於是異步操作,所以會新建一個線程。又由於參加到串行隊列中,所以一切的操作只會按順序執行。

2015-11-23 01:03:22.372 01.GCD演練[2081:3627139] 串行隊列 -- 異步義務 <NSThread: 0x7fb593d42f50>{number = 2, name = (null)} 0
2015-11-23 01:03:23.373 01.GCD演練[2081:3627139] 串行隊列 -- 異步義務 <NSThread: 0x7fb593d42f50>{number = 2, name = (null)} 1
2015-11-23 01:03:24.374 01.GCD演練[2081:3627139] 串行隊列 -- 異步義務 <NSThread: 0x7fb593d42f50>{number = 2, name = (null)} 2
2015-11-23 01:03:25.375 01.GCD演練[2081:3627139] 串行隊列 -- 異步義務 <NSThread: 0x7fb593d42f50>{number = 2, name = (null)} 3
2015-11-23 01:03:26.376 01.GCD演練[2081:3627139] 串行隊列 -- 異步義務 <NSThread: 0x7fb593d42f50>{number = 2, name = (null)} 4

3.異步操作,並行隊列

?

1

2

3

4

5

6

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

for(inti = 0; i < 5; ++i){

dispatch_async(q_concurrent, ^{

NSLog(@"並行隊列 -- 異步義務 %@ %d", [NSThread currentThread], i);

});

}

實際上並行隊列會給每一個異步操作新建線程,然後讓一切的義務並發執行。但是實踐上零碎能創立的線程數量是無限的,當創立的線程到達最大線程數當前,前面的異步操作就需求等候後面的操作執行終了才干失掉執行。哪個線程操作執行終了,就把等候的異步義務布置到哪個線程。直到一切的操作執行終了。你可以把上述代碼的循環次數改成5000就可以察看到此景象。

2015-11-23 01:14:15.282 01.GCD演練[2165:3634728] 並行隊列 -- 異步義務 <NSThread: 0x7fb3b841b0a0>{number = 4, name = (null)} 3
2015-11-23 01:14:15.282 01.GCD演練[2165:3634724] 並行隊列 -- 異步義務 <NSThread: 0x7fb3b8514da0>{number = 3, name = (null)} 0
2015-11-23 01:14:15.282 01.GCD演練[2165:3634726] 並行隊列 -- 異步義務 <NSThread: 0x7fb3b8604db0>{number = 5, name = (null)} 2
2015-11-23 01:14:15.282 01.GCD演練[2165:3634725] 並行隊列 -- 異步義務 <NSThread: 0x7fb3b86119d0>{number = 2, name = (null)} 1
2015-11-23 01:14:15.285 01.GCD演練[2165:3634729] 並行隊列 -- 異步義務 <NSThread: 0x7fb3b87011f0>{number = 6, name = (null)} 4

3.NSOperation & NSOperationQueue

雖然GCD的功用曾經很弱小了,但是它運用的API仍然是C言語的。在某些時分,在面向對象的objective-c中運用起來十分的不方便和不平安。

所以蘋果公司把GCD中的操作籠統成NSOperation對象,把隊列籠統成NSOperationQueue對象。

在IOS中為什麼使用多線程及多線程實現的三種方法
在IOS中為什麼使用多線程及多線程實現的三種方法

籠統為NSOperation & NSOperationQueue當前的益處有一下幾點:

代碼風格一致了,我們不必在面向對象的objective-C中寫面對進程的C言語代碼了。
我們知道在GCD中操作的執行代碼都是寫在匿名的block外面,那麼我們很難做到給操作設置依賴關系以及取消操作。這些功用都曾經封裝到NSOperation對象外面了。^-^
NSOperationQueue對象比GCD中隊列愈加的弱小和靈敏,比方:設置並發操作數量,取消隊列中一切操作。
NSOperation分為NSInvocationOperation和NSBlockOperation

NSInvocationOperation的運用

?

1

2

3

4

5

6

7

8

//首先定義一個NSOperationQueue對象

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

NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithtarget:self selector:@selector(operationAction:) object:@"這裡可以穿參數"];

[queue addOperation:op];//把操作參加隊列中即開端執行

- (void)operationAction:(id)obj

{

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

}

輸入為:

2015-11-23 02:55:19.067 多線程demo[2604:3686934] <NSThread: 0x7f9dfa443510>{number = 2, name = (null)} - obj : 這裡可以穿參數

NSBlockOperation的運用

?

1

2

3

4

5

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] <NSThread: 0x7fa983f10a50>{number = 2, name = (null)} - obj : 這是NSBlockOperation

設置依賴關系(執行順序)

?

1

2

3

4

5

6

7

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之後執行

[op2 addDependency:op1];//這裡需求留意,一定要在addOperation之前設置依賴關系

[queue addOperation:op1];

[queue addOperation:op2];

輸入為:

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

沒有設置依賴關系的輸入:

2015-11-23 03:00:45.939 多線程demo[2709:3692307] <NSThread: 0x7fe951d0d8a0>{number = 2, name = (null)} - obj : op2
2015-11-23 03:00:45.939 多線程demo[2709:3692308] <NSThread: 0x7fe951c24720>{number = 3, name = (null)} - obj : op1

到這裡你應該發現了,在NSOperation & NSOperationQueue中,我們不需求再像GCD那樣定義操作的類型和隊列的類型和控制操作的執行順序了,你只需求直接設定操作的執行順序就可以了。

【在IOS中為什麼運用多線程及多線程完成的三種辦法】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved