版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.08.16 |
前言
ios
中有串行和并行、同步和異步的概念贤徒,這些概念并不難,但是仍然需要大家好好的理解汇四,這一篇就詳細(xì)的和大家說說它們之間的關(guān)系接奈,希望對大家有所幫助。
同異步和串并行之間的關(guān)系
首先我們看一下ios
中同異步和隊列串并行的關(guān)系通孽,看一張很常見和經(jīng)典的圖序宦。
這張圖很好的把他們的關(guān)系全部總結(jié)出來了,剩下的就看大家的理解了背苦。
串行和并行
我們先看一下隊列的概念互捌。
隊列是先進先出(FIFO)
結(jié)構(gòu)的,其主要的任務(wù)主要是負(fù)責(zé)線程的創(chuàng)建糠惫、回收工作疫剃,不論什么隊列和什么任務(wù)都不需要程序員參與,減輕了程序員的工作硼讽。
隊列主要分為:
-
GCD
隊列- 運行在主線程中的主隊列。
- 3 個不同優(yōu)先級的后臺隊列牲阁。
- 一個優(yōu)先級更低的后臺隊列(用于 I/O)固阁。
- 自定義隊列
- 串行隊列
- 并行隊列。
- 自定義隊列非常強大城菊,建議在開發(fā)中使用备燃。在自定義隊列中被調(diào)度的所有Block最終都將被放入到系統(tǒng)的全局隊列中和線程池中。
下面看一張非常重要的圖凌唬。
從圖中可以看出串行隊列并齐、并行隊列都屬于默認(rèn)優(yōu)先級的GCD
隊列。
1. 串行
串行是一次只能執(zhí)行一個任務(wù)。讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后况褪,再執(zhí)行下一個任務(wù))撕贞。
2. 并行
并行是一次能執(zhí)行多個任務(wù)〔舛猓可以讓多個任務(wù)并發(fā)(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))捏膨,并發(fā)功能只有在異步函數(shù)下才有效。
同步和異步
1. 同步
所謂同步食侮,就是在發(fā)出一個調(diào)用
時号涯,在沒有得到結(jié)果之前,該調(diào)用就不返回锯七。但是一旦調(diào)用返回链快,就得到返回值了。注意這個返回是指CUP返回執(zhí)行的數(shù)據(jù)段部分眉尸,所以目前來看只是阻塞了CPU的數(shù)據(jù)段部分 并不耽誤CPU干別的 所以即使是同步也不見得是阻塞模式
換句話說久又,就是由調(diào)用者
主動等待這個調(diào)用
的結(jié)果。
2. 異步
所謂異步效五,就是調(diào)用
在發(fā)出之后地消,這個調(diào)用就直接返回了,所以沒有返回結(jié)果畏妖。換句話說脉执,當(dāng)一個異步過程調(diào)用發(fā)出后,調(diào)用者不會立刻得到結(jié)果戒劫。而是在調(diào)用
發(fā)出后半夷,被調(diào)用者
通過狀態(tài)、通知來通知調(diào)用者迅细,或通過回調(diào)函數(shù)處理這個調(diào)用巫橄。
幾個重要例子
1. 串行隊列 + 異步任務(wù)
下面直接看代碼。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self serialAndAsync];
}
#pragma mark - Object Private Function
//串行隊列 + 異步任務(wù)
- (void)serialAndAsync
{
//串行隊列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_async(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 22:37:20.295 JJOC[1512:40834] 0--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.296 JJOC[1512:40834] 1--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.296 JJOC[1512:40834] 2--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.296 JJOC[1512:40834] 3--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.296 JJOC[1512:40834] 4--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.297 JJOC[1512:40834] 5--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.297 JJOC[1512:40834] 6--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.297 JJOC[1512:40834] 7--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.297 JJOC[1512:40834] 8--<NSThread: 0x600000265440>{number = 3, name = (null)}
2017-08-16 22:37:20.298 JJOC[1512:40834] 9--<NSThread: 0x600000265440>{number = 3, name = (null)}
結(jié)論:由上可知
- 開啟了新的線程
- 任務(wù)是串行執(zhí)行的茵典。
2. 串行隊列 + 同步任務(wù)
下面還是直接看代碼湘换。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self serialAndSync];
}
#pragma mark - Object Private Function
//串行隊列 + 同步任務(wù)
- (void)serialAndSync
{
//串行隊列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_sync(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 22:41:37.427 JJOC[1661:44282] 0--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.428 JJOC[1661:44282] 1--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.428 JJOC[1661:44282] 2--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.428 JJOC[1661:44282] 3--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.429 JJOC[1661:44282] 4--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.429 JJOC[1661:44282] 5--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.429 JJOC[1661:44282] 6--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.429 JJOC[1661:44282] 7--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.429 JJOC[1661:44282] 8--<NSThread: 0x6000000643c0>{number = 1, name = main}
2017-08-16 22:41:37.430 JJOC[1661:44282] 9--<NSThread: 0x6000000643c0>{number = 1, name = main}
結(jié)論:由上可知
- 沒有開啟了新的線程,還是在主線程中執(zhí)行统阿。
- 任務(wù)是串行執(zhí)行的彩倚。
3. 并發(fā)隊列 + 異步任務(wù)
還是直接看代碼。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self concurrentAndAsync];
}
#pragma mark - Object Private Function
//并發(fā)隊列 + 異步任務(wù)
- (void)concurrentAndAsync
{
//并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_async(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 22:50:09.200 JJOC[1946:50520] 1--<NSThread: 0x60800006cdc0>{number = 4, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50517] 2--<NSThread: 0x600000073c40>{number = 5, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50518] 0--<NSThread: 0x60800006ca00>{number = 3, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50539] 3--<NSThread: 0x600000073d40>{number = 6, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50540] 4--<NSThread: 0x600000073c80>{number = 7, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50520] 5--<NSThread: 0x60800006cdc0>{number = 4, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50517] 6--<NSThread: 0x600000073c40>{number = 5, name = (null)}
2017-08-16 22:50:09.200 JJOC[1946:50518] 7--<NSThread: 0x60800006ca00>{number = 3, name = (null)}
2017-08-16 22:50:09.201 JJOC[1946:50541] 8--<NSThread: 0x600000073880>{number = 8, name = (null)}
2017-08-16 22:50:09.201 JJOC[1946:50539] 9--<NSThread: 0x600000073d40>{number = 6, name = (null)}
結(jié)論:由上可知
- 開啟了新的線程扶平。
- 任務(wù)是并發(fā)執(zhí)行的帆离。
4. 并發(fā)隊列 + 同步任務(wù)
下面看代碼。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self concurrentAndSync];
}
#pragma mark - Object Private Function
//并發(fā)隊列 + 同步任務(wù)
- (void)concurrentAndSync
{
//并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_sync(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 22:57:16.705 JJOC[2271:56082] 0--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.706 JJOC[2271:56082] 1--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.706 JJOC[2271:56082] 2--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.706 JJOC[2271:56082] 3--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.706 JJOC[2271:56082] 4--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.707 JJOC[2271:56082] 5--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.707 JJOC[2271:56082] 6--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.707 JJOC[2271:56082] 7--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.707 JJOC[2271:56082] 8--<NSThread: 0x608000068540>{number = 1, name = main}
2017-08-16 22:57:16.707 JJOC[2271:56082] 9--<NSThread: 0x608000068540>{number = 1, name = main}
結(jié)論:由上可知
- 沒有開啟新的線程结澄。
- 任務(wù)是串行執(zhí)行的哥谷。
5. 主隊列 + 同步任務(wù)
看代碼岸夯。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self mainAndSync];
}
#pragma mark - Object Private Function
//主隊列 + 同步任務(wù)
- (void)mainAndSync
{
//主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"線程 = %@",[NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"thread = %@",[NSThread currentThread]);
});
NSLog(@"我被阻塞了");
}
@end
下面看輸出結(jié)果
2017-08-16 23:20:23.406 JJOC[2985:72806] 線程 = <NSThread: 0x600000067340>{number = 1, name = main}
結(jié)論:由上可知NSLog(@"我被阻塞了");
并沒有執(zhí)行和輸出,也就是說主線程發(fā)生了死鎖们妥。這里要說一下發(fā)生死鎖的原因:在主隊列開啟同步任務(wù)猜扮,因為主隊列是串行隊列,里面的線程是有順序的王悍,先執(zhí)行完一個線程才執(zhí)行下一個線程破镰,而主隊列始終就只有一個主線程,主線程是不會執(zhí)行完畢的压储,因為他是無限循環(huán)的鲜漩,除非關(guān)閉應(yīng)用程序。因此在主線程開啟一個同步任務(wù)集惋,同步任務(wù)會想搶占執(zhí)行的資源孕似,而主線程任務(wù)一直在執(zhí)行某些操作,不肯放手刮刑。兩個的優(yōu)先級都很高喉祭,最終導(dǎo)致死鎖,阻塞線程了雷绢。
6. 主隊列 + 異步任務(wù)
下面還是直接看代碼泛烙。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self mainAndAsync];
}
#pragma mark - Object Private Function
//主隊列 + 異步任務(wù)
- (void)mainAndAsync
{
//主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_async(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 23:26:27.616 JJOC[3226:78118] 0--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.616 JJOC[3226:78118] 1--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.616 JJOC[3226:78118] 2--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.617 JJOC[3226:78118] 3--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.617 JJOC[3226:78118] 4--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.617 JJOC[3226:78118] 5--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.617 JJOC[3226:78118] 6--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.618 JJOC[3226:78118] 7--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.618 JJOC[3226:78118] 8--<NSThread: 0x600000077ac0>{number = 1, name = main}
2017-08-16 23:26:27.618 JJOC[3226:78118] 9--<NSThread: 0x600000077ac0>{number = 1, name = main}
結(jié)論:由上可知
- 沒有開啟新的線程,主隊列只有主線程翘紊。
- 任務(wù)是串行執(zhí)行的蔽氨。
7. 全局隊列 + 同步任務(wù)
直接看代碼。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self mainAndAsync];
}
#pragma mark - Object Private Function
//全局隊列 + 同步任務(wù)
- (void)globalAndSync
{
//全局隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_sync(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 23:31:38.182 JJOC[3381:82695] 0--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.183 JJOC[3381:82695] 1--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.183 JJOC[3381:82695] 2--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.183 JJOC[3381:82695] 3--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.184 JJOC[3381:82695] 4--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.184 JJOC[3381:82695] 5--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.184 JJOC[3381:82695] 6--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.184 JJOC[3381:82695] 7--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.184 JJOC[3381:82695] 8--<NSThread: 0x600000068a80>{number = 1, name = main}
2017-08-16 23:31:38.185 JJOC[3381:82695] 9--<NSThread: 0x600000068a80>{number = 1, name = main}
結(jié)論:由上可知
- 沒有開啟新的線程帆疟。
- 任務(wù)是串行執(zhí)行的鹉究。
8. 全局隊列 + 異步任務(wù)
下面還是直接看代碼。
#import "JJQueueStatusVC.h"
@interface JJQueueStatusVC ()
@end
@implementation JJQueueStatusVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self globalAndAsync];
}
#pragma mark - Object Private Function
//全局隊列 + 異步任務(wù)
- (void)globalAndAsync
{
//全局隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSInteger i = 0; i < 10; i ++) {
//創(chuàng)建要執(zhí)行的任務(wù)
void(^task)() = ^{
NSLog(@"%ld--%@",i, [NSThread currentThread]);
};
//將任務(wù)添加到隊列
dispatch_async(queue, task);
}
}
@end
下面看輸出結(jié)果
2017-08-16 23:34:46.735 JJOC[3515:85791] 2--<NSThread: 0x608000261c00>{number = 5, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85790] 0--<NSThread: 0x608000261600>{number = 3, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85809] 1--<NSThread: 0x600000268080>{number = 4, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85793] 3--<NSThread: 0x600000268400>{number = 6, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85811] 4--<NSThread: 0x608000262380>{number = 7, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85791] 6--<NSThread: 0x608000261c00>{number = 5, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85812] 5--<NSThread: 0x608000262700>{number = 8, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85790] 7--<NSThread: 0x608000261600>{number = 3, name = (null)}
2017-08-16 23:34:46.735 JJOC[3515:85813] 8--<NSThread: 0x608000262740>{number = 9, name = (null)}
2017-08-16 23:34:46.736 JJOC[3515:85809] 9--<NSThread: 0x600000268080>{number = 4, name = (null)}
結(jié)論:由上可知
- 開啟新的線程踪宠。
- 任務(wù)是并行執(zhí)行的自赔。
參考文章
1. iOS中多線程知識總結(jié):進程、線程柳琢、GCD绍妨、串行隊列、并行隊列染厅、全局隊列痘绎、主線程隊列、同步任務(wù)肖粮、異步任務(wù)等(有示例代碼)
后記
未完,待續(xù)~~~