一、進程編程
進程是指在系統中正在運行的一個應用程序,每一個進程之間是獨立的,每一個進程均運行在其專用且受保護的內存空間內;網絡
若是咱們把CPU比做一個工廠,那麼進程就比如工廠的車間,一個工廠有好多個車間,每一個車間都在進行不一樣的工做,它們之間是獨立互不干擾的。多線程
二、線程併發
線程是進程的基本執行單元,一個進程的全部任務都在線程中執行;一個進程要想執行任務,必須得有線程(每一個進程至少要有1條線程);app
線程就比如車間裏的工人,一個車間裏能夠有好多工人(一個進程能夠包括多個線程),他們協同完成一個任務;異步
多線程是一個比較輕量級的方法來實現單個應用程序內多個代碼執行路徑。async
一個進程中能夠開啓多條線程,每條線程能夠並行(同時)執行不一樣的任務,能夠提升程序的執行效率;函數
原理:同一時間,CPU只能處理1條線程,只有1條線程在工做(執行);多線程併發(同時)執行,實際上是CPU快速地在多條線程之間調度(切換)若是CPU調度線程的時間足夠快,就形成了多線程併發執行的假象。oop
優缺點:
性能
多線程的優勢:
(1)能適當提升程序的執行效率
(2)能適當提升資源利用率(CPU、內存利用率)
多線程的缺點:
(1)開啓線程須要佔用必定的內存空間(默認狀況下,主線程佔用1M,子線程佔用512KB),若是開啓大量的線程,會佔用大量的內存空間,下降程序的性能
線程越多,CPU在調度線程上的開銷就越大
(2)程序設計更加複雜:好比線程之間的通訊、多線程的數據共享
iOS中幾種多線程實現:
一、Thread
二、Cocoa operations
三、GCD(Grand Central Dispatch)(iOS4 以後)
一、NSThread
(1)NSThread有兩種建立方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument;
//實例方法 thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:nil];
//啓動線程 [thread start]; //類方法 [NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:nil];
selector :線程執行的方法,selector只能有一個參數,且不能有返回值;
target :selector消息發送的對象;
object :傳輸給target的惟一參數,也能夠是nil;
兩種建立方式的不一樣:
類方法一調用就會當即建立一個線程來作事情;
實例方法要直到咱們手動調用 start 啓動線程時纔會真正去建立線程;
(2)不顯式建立線程的方法(間接建立):
利用NSObject的方法 performSelectorInBackground:withObject:來建立;
//隱含產生新線程
[myView performSelectorInBackground:@selector(Action:) withObject:nil];
(3)NSThread相關屬性及方法:
@property (copy) NSString *name; // 獲取/設置線程的名字
+ (NSThread *)currentThread; // 獲取當前線程的線程對象
+ (void)sleepForTimeInterval:(NSTimeInterval)ti; // 線程休眠(秒)
+ (void)sleepUntilDate:(NSDate *)date; // 線程休眠,指定具體什麼時間休眠
+ (void)exit; // 退出線程(線程對象銷燬,銷燬後就不能再次啓動線程,不然程序會崩潰)
二、NSOperation
(1)NSInvocationOperation
NSInvocationOperation的建立:
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction) object:nil];//object能夠帶一個參數
//啓動線程,默認是不啓動 [operation start];
- (void)operationAction{}
參數和NSTread同樣。
(2)NSBlockOperation
NSBlockOperation 是 NSOperation 類的另一個系統預約義的子類,咱們能夠用它來封裝一個或多個 block。
通常來講,有如下兩個場景咱們會優先使用 NSBlockOperation 類:
當咱們在應用中已經使用了 Operation Queues 且不想建立 Dispatch Queues 時,NSBlockOperation 類能夠爲咱們的應用提供一個面向對象的封裝;
咱們須要用到 Dispatch Queues 不具有的功能時,好比須要設置 operation 之間的依賴關係、使用 KVO 觀察 operation 的狀態變化等;
NSBlockOperation的建立:
咱們可使它併發執行,經過使用addExecutionBlock方法添加多個Block,這樣就能使它在主線程和其它子線程中工做。
- (NSBlockOperation*)blockOperation{ NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"block1,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); }]; [blockOperation addExecutionBlock:^{ NSLog(@"block2,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); NSLog(@"Finish block2"); }]; [blockOperation addExecutionBlock:^{ NSLog(@"block3,mainThread:%@,currebtThread:%@",[NSThread mainThread],[NSThread currentThread]); NSLog(@"Finish block3"); }]; return blockOperation; }
(3)NSOperationQueue
一個NSOperation對象能夠經過調用start方法來執行任務,默認是同步執行的;也能夠將NSOperation添加到一個NSOperationQueue(操做隊列)中去執行,並且是異步執行的。
一、NSOperation方法及屬性:
// 設置線程的最大併發數 @property NSInteger maxConcurrentOperationCount; // 線程完成後調用的Block @property (copy) void (^completionBlock)(void); // 取消線程 - (void)cancel;
二、建立一個操做隊列:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
三、添加NSOperation到NSOperationQueue中:
//添加一個operation [operationQueue addOperation:operation]; //添加一組operation NSArray *operations = [NSArray arrayWithObjects:@"",@"", nil]; [operationQueue addOperations:operations waitUntilFinished:NO]; //添加一個block形式的operation [operationQueue addOperationWithBlock:^() { NSLog(@"blockOperation:%@", [NSThread currentThread]); }];
四、設置NSOperation的依賴對象
(1)當某個NSOperation對象依賴於其它NSOperation對象的完成時,就能夠經過addDependency方法添加一個或者多個依賴的對象,只有全部依賴的對象都已經完成操做,當前NSOperation對象纔會開始執行操做。經過removeDependency方法來刪除依賴對象。
以下代碼:operation1依賴operation2,意思爲先執行operation2,operation2完成後繼續執行operation1;
[operation2 addDependency:operation1];
刪除依賴對象,刪除後則不存在依賴關係;以下代碼:
[operation2 removeDependency:operation1];
(2)沒有設置依賴關係的狀況下:(默認)
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"執行第1次操做:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"執行第2次操做:%@", [NSThread currentThread]); }]; [operationQueue addOperation:operation1]; [operationQueue addOperation:operation2];
打印:
由打印信息能夠看出,默認是按順序進行的;
(3)設置依賴關係的狀況下:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"執行第1次操做:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"執行第2次操做:%@", [NSThread currentThread]); }]; [operation1 addDependency:operation2]; [operationQueue addOperation:operation1]; [operationQueue addOperation:operation2];
打印:
能夠看出程序先執行operation2,後執行operation1。
若是要解除依賴關係,則:
[operation1 removeDependency:operation2];
注意:在NSOperationQueue類中,咱們可使用cancelAllOperations方法取消全部的線程。這裏須要注意一下,不是執行cancelAllOperations方法時就會立刻取消,是等當前隊列執行完,下面的隊列不會再執行。
三、 GCD(Grand Central Dispatch)
GCD 是Apple公司開發的一種技術,異步執行任務的技術之一,它旨在優化多核環境中的併發操做並取代傳統多線程的編程模式;在Mac OS X 10.6和IOS 4.0以後開始支持GCD。
工做原理:讓程序平行排隊的特定任務,根據可用的處理資源,安排他們在任何可用的處理器核心上執行任務。
GCD中的FIFO(First In First Out)隊列稱爲dispatch queue,它能夠保證先進來的任務先獲得執行;
Dispatch Queue分三種:
(1)Main queue:main dispatch queue 是一個全局可用的串行隊列,在應用程序的主線程上執行任務。此隊列的任務和應用程序的主循環(run loop)要執行的事件源交替執行。由於運行在應用程序的主線程,main queue常常用來做爲應用程序的一個同步點。
(2)Serial quque: 又稱private dispatch queue(私有調度隊列),每次運行一個任務,能夠添加多個,執行次序FIFO,通常用再對特定資源的同步訪問上。咱們能夠根據須要建立任意數量的串行隊列,每個串行隊列之間是併發的。
(3)Concurrent queue: 又稱爲global dispatch queue,能夠併發地執行多個任務,可是執行完成的順序是隨機的.
使用方法:
(1)dispatch_async
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
async代表異步運行,除了async,還有sync(同步),delay(延時);
block表明的是你要作的事情;
queue則是你把任務交給誰來處理了;
dispatch_async 這個函數是異步的,這就意味着它會當即返回而無論block是否運行結束。所以,咱們能夠在block裏運行各類耗時的操做(如網絡請求) 而同時不會阻塞UI線程。
舉個例子看看它的實際用法:(下載一張圖片)
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:imageView]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL *url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/h%3D200/sign=5dafb2a3586034a836e2bf81fb1249d9/d31b0ef41bd5ad6e194e5f4885cb39dbb7fd3cd8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [[UIImage alloc] initWithData:data]; if (data) { dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = image; }); } }); }
運行:
比起NSThread和NSOperation用法是否是簡單多了。
系統給每個應用程序提供了四個concurrent dispatch queues,這四個併發調度隊列是全局的,它們只有優先級的不一樣;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group1"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"group2"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group3"); });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"print");
});
打印:
(3)dispatch_barrier_async
dispatch_barrier_async是在前面的任務執行結束後它才執行,並且它後面的任務等它執行完成以後纔會執行;
dispatch_queue_t queue = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"queue1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"queue2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"queue3"); });
打印:
(4)dispatch_apply
執行某個代碼片斷幾回。
dispatch_apply(2, globalQ, ^(size_t index) {
// 執行2次
});
(5)dispatch_suspend/dispatch_resume