你好,歡迎來到IOS教程網

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

在IOS中為何應用多線程及多線程完成的三種辦法

編輯:IOS開發綜合

多線程是一個比擬輕量級的辦法來完成單個運用法式內多個代碼履行途徑。

在體系級別內,法式並排履行,法式分派到每一個法式的履行時光是基於該法式的所需時光和其他法式的所需時光來決議的。

但是,在每一個法式外部,存在一個或許多個履行線程,它同時或在一個簡直同時產生的方法裡履行分歧的義務。

概要提醒:

iPhone中的線程運用其實不是無控制的,官方給出的材料顯示,iPhone OS下的主線程的客棧年夜小是1M,第二個線程開端就是512KB,而且該值不克不及經由過程編譯器開關或線程API函數來更改,只要主線程有直接修正UI的才能

1、線程概述

有些法式是一條直線,終點到起點——如簡略的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停止調試,在現實項目中不推舉應用。

//獲得以後線程
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

壅塞線程:

//壅塞線程3秒
[NSThread sleepForTimeInterval:3];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];

2.GCD(Grand Central Dispatch)

GCD是基於C說話底層API完成的一套多線程並發機制,異常的靈巧便利,在現實的開辟中應用很普遍。

簡略來講CGD就是把 操作 放在 隊列 中去履行。

你只需界說好操作和隊列便可以了,不須要直接掌握線程的創立和燒毀,線程的性命周期由隊列來治理。

隊列:擔任操作的調劑和履行,有先輩先出(FIFO)的特色。也就是說先參加隊列的操作先履行,後參加的後履行。

隊列有兩種:

串行隊列:

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

並行隊列:

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

//創立串行隊列
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是曾經界說好的,操作要參加的隊列

//界說同步操作
dispatch_sync(q, ^{
 //要履行的代碼 
});
//界說異步操作
dispatch_async(q, ^{
 //要履行的代碼  
});

上面我們看一下同步,異步操作參加到串行和並行隊列外面,履行的次序和特色:1.同步操作不論參加到何種隊列,只會在主線程按次序履行

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 < 5; ++i) {
 dispatch_sync(q_serial, ^{
 NSLog(@"串行隊列裡的同步義務 %@ %d", [NSThread currentThread], i);
 });
}
for (int i = 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.異步操作只在非主線程的線程履行,在串行隊列中異步操作會在新建的線程中按次序履行。

 dispatch_queue_t q_serial = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);
 for(int i = 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.異步操作,並行隊列

 dispatch_queue_t q_concurrent = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
 for(int i = 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對象。


籠統為NSOperation & NSOperationQueue今後的利益有一下幾點:

代碼作風同一了,我們不消在面向對象的objective-C中寫面臨進程的C說話代碼了。
我們曉得在GCD中操作的履行代碼都是寫在匿名的block外面,那末我們很難做到給操作設置依附關系和撤消操作。這些功效都曾經封裝到NSOperation對象外面了。^-^
NSOperationQueue對象比GCD中隊列加倍的壯大和靈巧,好比:設置並發操作數目,撤消隊列中一切操作。
NSOperation分為NSInvocationOperation和NSBlockOperation

NSInvocationOperation的應用

//起首界說一個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的應用

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

設置依附關系(履行次序)

 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