NSThread
有三種方式可以開Thread
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test:) object:nil];
[NSThread detachNewThreadSelector:@selector(test:) toTarget:self withObject:@"分离子线程"];
[self performSelectorInBackground:@selector(test:) withObject:@"后台线程"];
第二三種方式直接開啟線程,但無法取得instance
performSelector是比較早期的API,跟NSThreadㄧ樣呼叫一次就開一個線程
目前Object-C大多使用GCD或是NSOperationQueue,這兩個API會自行管理線程數量
GCD
分作兩種模式
- dispatch_async :非同步
- dispatch_sync:同步
個人感覺有點類似C#的async Task 搭配 await語法,會把工作丟給別的Thread去做,但會等工作做完才繼續動作
實際上使用dispatch_sync後,發現動作並沒有在其他Thread執行,而是使用main thread,爬文之後發現有人在討論這個問題
也就是說因為main queue是serial queue,呼叫dispatch_sync必定導致線程block住,無所謂執行block內工作的線程,所以程式會直接使用main queue執行,節省開線程的資源
如果今天是在背景呼叫dispatch_sync把工作丟給main queue,就會有線程切換的動作
簡單來說 dispatch_sync 不會開新線程,但在特定情況下,會有線程切換
另外使用dispatch_async也不一定呼叫幾次就開啟多少線程,程式會自行控制
推測應該跟C#一樣使用thread pool的概念
有文章說線程上限66個,serial 與 concurrent共用這數量
有文章說線程上限66個,serial 與 concurrent共用這數量
dispatch_queue 可以分為兩種,serial queue與concurrent queue
main_queue:serial queue
global_queue:於concurrent queue
用dispatch_queue_t可以自行宣告,自行決定類型
GCD使用方法
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//sync呼叫 會在main queue執行 | |
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
for(int i=0;i<5;i++){ | |
NSLog(@"sync: %d %@",i, [NSThread currentThread]); | |
} | |
}); | |
//2018-04-30 16:42:57.905789+0800 NSTimer_NSRunLoop[4045:160977] sync: 0 <NSThread: 0x604000065540>{number = 1, name = main} | |
//2018-04-30 16:42:57.905875+0800 NSTimer_NSRunLoop[4045:160977] sync: 1 <NSThread: 0x604000065540>{number = 1, name = main} | |
//2018-04-30 16:42:57.905904+0800 NSTimer_NSRunLoop[4045:160977] sync: 2 <NSThread: 0x604000065540>{number = 1, name = main} | |
//2018-04-30 16:42:57.905929+0800 NSTimer_NSRunLoop[4045:160977] sync: 3 <NSThread: 0x604000065540>{number = 1, name = main} | |
//2018-04-30 16:42:57.905951+0800 NSTimer_NSRunLoop[4045:160977] sync: 4 <NSThread: 0x604000065540>{number = 1, name = main} | |
sleep(1); | |
//async global queue | |
//global queue都是concurrent,所以印出來的結果會是亂序 | |
for(int i=0;i<5;i++){ | |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
NSLog(@"global: %d %@",i, [NSThread currentThread]); | |
}); | |
} | |
//2018-04-30 16:42:58.907260+0800 NSTimer_NSRunLoop[4045:161039] global: 3 <NSThread: 0x604000460240>{number = 5, name = (null)} | |
//2018-04-30 16:42:58.907258+0800 NSTimer_NSRunLoop[4045:161045] global: 1 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:42:58.907299+0800 NSTimer_NSRunLoop[4045:161061] global: 4 <NSThread: 0x60000007d080>{number = 6, name = (null)} | |
//2018-04-30 16:42:58.907258+0800 NSTimer_NSRunLoop[4045:161040] global: 2 <NSThread: 0x60000007cf00>{number = 4, name = (null)} | |
//2018-04-30 16:42:58.907258+0800 NSTimer_NSRunLoop[4045:161038] global: 0 <NSThread: 0x604000460040>{number = 2, name = (null)} | |
sleep(1); | |
//自行建立serial queue,會按照順序執行工作 | |
dispatch_queue_t serialQueue = \ | |
dispatch_queue_create("thread4", DISPATCH_QUEUE_SERIAL); | |
for(int i=0;i<5;i++){ | |
dispatch_async(serialQueue, ^{ | |
NSLog(@"serial queue %d %@",i, [NSThread currentThread]); | |
}); | |
} | |
//2018-04-30 16:42:59.908440+0800 NSTimer_NSRunLoop[4045:161045] serial queue 0 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:42:59.908514+0800 NSTimer_NSRunLoop[4045:161045] serial queue 1 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:42:59.908541+0800 NSTimer_NSRunLoop[4045:161045] serial queue 2 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:42:59.908561+0800 NSTimer_NSRunLoop[4045:161045] serial queue 3 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:42:59.908579+0800 NSTimer_NSRunLoop[4045:161045] serial queue 4 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
sleep(1); | |
//自行建立concurrent queue | |
dispatch_queue_t concurrentQueue = \ | |
dispatch_queue_create("thread5", DISPATCH_QUEUE_CONCURRENT); | |
for(int i=0;i<5;i++){ | |
dispatch_async(concurrentQueue, ^{ | |
NSLog(@"concurrent queue %d %@",i, [NSThread currentThread]); | |
}); | |
} | |
//2018-04-30 16:43:00.909678+0800 NSTimer_NSRunLoop[4045:161045] concurrent queue 0 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} | |
//2018-04-30 16:43:00.909678+0800 NSTimer_NSRunLoop[4045:161040] concurrent queue 2 <NSThread: 0x60000007cf00>{number = 4, name = (null)} | |
//2018-04-30 16:43:00.909746+0800 NSTimer_NSRunLoop[4045:161061] concurrent queue 3 <NSThread: 0x60000007d080>{number = 6, name = (null)} | |
//2018-04-30 16:43:00.909678+0800 NSTimer_NSRunLoop[4045:161038] concurrent queue 1 <NSThread: 0x604000460040>{number = 2, name = (null)} | |
//2018-04-30 16:43:00.909757+0800 NSTimer_NSRunLoop[4045:161045] concurrent queue 4 <NSThread: 0x60000007d5c0>{number = 3, name = (null)} |
類似於async await,之後會詳細描述
http://www.iosxxx.com/blog/2016-06-02-GCD那些事.html