【iOS】多线程梳理

【iOS】多线程梳理

【iOS】多线程整理

Pthreads(不常用)

POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX规范。该规范界说了创立和操纵线程的一整套API。在类Unix操作体系(Unix、Linux、Mac OS X等)中,都运用Pthreads作为操作体系的线程。

实践

用Pthreads创立一个线程去履行一个使命

- (void)touchesPthread {
    NSLog(@"====================== touchesPthread START ======================");
    pthread_t thread = NULL;
    NSString *params = @"Hello World";
    int result = pthread_create(&thread, NULL, threadTask, (__bridge void *)(params));
    result == 0 ? NSLog(@"creat thread success") : NSLog(@"creat thread failure");
    // 设置子线程的状况设置为detached,则该线程运行结束后会主动释放一切资源
    // 毁掉推迟, 用来推迟运用(sleep)
    [NSThread sleepForTimeInterval:5];
    pthread_detach(thread);
    NSLog(@"====================== touchesPthread END ======================");
}
void *threadTask(void *params) {
    NSLog(@"%@ - %@", [NSThread currentThread], (__bridge NSString *)(params));
    NSLog(@"threadTask end");
    return NULL;
}

毁掉不推迟

2022-08-08 23:39:39.018287+0800 OneLiveIOS[2909:62998] ====================== touchesPthread START ======================
2022-08-08 23:39:39.018549+0800 OneLiveIOS[2909:62998] creat thread success
2022-08-08 23:39:39.018585+0800 OneLiveIOS[2909:62998] ====================== touchesPthread END ======================

毁掉推迟

2022-08-08 23:43:35.245019+0800 OneLiveIOS[3035:67075] ====================== touchesPthread START ======================
2022-08-08 23:43:35.245300+0800 OneLiveIOS[3035:67075] creat thread success
2022-08-08 23:43:35.245434+0800 OneLiveIOS[3035:67099] <NSThread: 0x100577770>{number = 2, name = (null)} - Hello World
2022-08-08 23:43:35.245452+0800 OneLiveIOS[3035:67099] threadTask end
2022-08-08 23:43:40.250522+0800 OneLiveIOS[3035:67075] ====================== touchesPthread END ======================
Program ended with exit code: 0

NSThread

NSThread的根本运用比较简单,能够动态创立初始化NSThread目标,对其进行设置然后发动;也能够经过NSThread的静态办法快速创立并发动新线程;此外NSObject基类目标还供给了隐式快速创立NSThread线程的performSelector系列类别扩展东西办法;NSThread还供给了一些静态东西接口来控制当时线程以及获取当时线程的一些信息。

体系API

@interface NSThread : NSObject
	// 当时线程
	@property (class, readonly, strong) NSThread *currentThread;
	// 运用类办法创立线程履行使命
	+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
	+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
	// 判断当时是否为多线程
	+ (BOOL)isMultiThreaded;
	// 指定线程的线程参数,例如设置当时线程的断语处理器。
	@property (readonly, retain) NSMutableDictionary *threadDictionary;
	// 当时线程暂停到某个时刻
	+ (void)sleepUntilDate:(NSDate *)date;
	// 当时线程暂停一段时刻
	+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
	// 退出当时线程
	+ (void)exit;
	// 当时线程优先级
	+ (double)threadPriority;
	// 设置当时线程优先级
	+ (BOOL)setThreadPriority:(double)p;
	// 指定线程目标优先级 0.0~1.0,默认值为0.5
	@property double threadPriority NS_AVAILABLE(10_6, 4_0);
	// 服务质量
	@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
	// 线程称号
	@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
	// 栈区巨细
	@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);
	// 是否为主线程
	@property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
	// 获取主线程
	@property (class, readonly, strong) NSThread *mainThread NS_AVAILABLE(10_5, 2_0);
	// 初始化
	- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
	// 实例办法初始化,需求再调用start办法
	- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
	- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
	// 线程状况,正在履行
	@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);
	// 线程状况,正在完结
	@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);
	//线程状况,已经撤销
	@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);
	// 撤销,仅仅改动线程状况,并不能像exist一样真实的终止线程
	- (void)cancel NS_AVAILABLE(10_5, 2_0);
	// 开端
	- (void)start NS_AVAILABLE(10_5, 2_0);
	// 线程需求履行的代码,一般写子类的时分会用到
	- (void)main NS_AVAILABLE(10_5, 2_0);
	@end
// NSObject的分类
@interface NSObject (NSThreadPerformAdditions)
	// 隐式的创立并发动线程,并在指定的线程(主线程或子线程)上履行办法。
	- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
	- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
	- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
	- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
	- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
@end

实践

- (void)touchesNSthread {
    NSLog(@"====================== touchesNSthread START ======================");
    NSLog(@"thread%@", [NSThread currentThread]);
    // NSThread静态东西办法
    // 1 是否敞开了多线程
    BOOL isMultiThreaded = [NSThread isMultiThreaded];
    NSLog(@"是否敞开了多线程, isMultiThreaded: %d", isMultiThreaded);
    // 2 获取当时线程
    NSThread *currentThread = [NSThread currentThread];
    // 3 获取主线程
    NSThread *mainThread = [NSThread mainThread];
    //NSLog(@"main thread, name: %@", [mainThread currentThread]);
    // 4 睡觉当时线程
    // 4.1 线程睡觉1s钟
    [NSThread sleepForTimeInterval:1];
    // 4.2 线程睡觉到指定时刻,效果同上
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    // 5 退出当时线程,留意不要在主线程调用,防止主线程被kill掉
    //[NSThread exit];     NSLog(@"main thread");
    // NSThread线程目标根本创立,target为入口函数地点的目标,selector为线程入口函数
    // 1 线程实例目标创立与设置
    NSThread *newThread= [[NSThread alloc] initWithTarget:self selector:@selector(NSthreadRun) object:nil];
    // 设置线程优先级threadPriority(0~1.0),即将被扔掉,将运用qualityOfService替代
    newThread.threadPriority = 1.0;
    newThread.qualityOfService = NSQualityOfServiceUserInteractive;
    // 敞开线程
    [newThread start];
    // 2 静态办法快速创立并敞开新线程
    [NSThread detachNewThreadSelector:@selector(NSthreadRun) toTarget:self withObject:nil];
    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"静态办法 block run...");
    }];
    // NSObejct基类隐式创立线程的一些静态东西办法
    // 1 在当时线程上履行办法,推迟2s
    [self performSelector:@selector(NSthreadRun) withObject:nil afterDelay:2.0];
    // 2 在指定线程上履行办法,不等候当时线程
    [self performSelector:@selector(NSthreadRun) onThread:newThread withObject:nil waitUntilDone:NO];
    // 3 后台异步履行函数
    [self performSelectorInBackground:@selector(NSthreadRun) withObject:nil];
    // 4 在主线程上履行函数
    [self performSelectorOnMainThread:@selector(NSthreadRun) withObject:nil waitUntilDone:NO];
    NSLog(@"====================== touchesNSthread END ======================");
}
- (void)NSthreadRun {
    NSLog(@"mxz NSthreadRun...");
}
2022-08-08 23:54:25.307552+0800 OneLiveIOS[3323:75768] ====================== touchesNSthread START ======================
2022-08-08 23:54:25.307916+0800 OneLiveIOS[3323:75768] thread<NSThread: 0x100705900>{number = 1, name = main}
2022-08-08 23:54:25.307955+0800 OneLiveIOS[3323:75768] 是否敞开了多线程, isMultiThreaded: 0
2022-08-08 23:54:27.319130+0800 OneLiveIOS[3323:76072] 静态办法 block run...
2022-08-08 23:54:27.319185+0800 OneLiveIOS[3323:76070] mxz NSthreadRun...
2022-08-08 23:54:27.319188+0800 OneLiveIOS[3323:76071] mxz NSthreadRun...
2022-08-08 23:54:27.319700+0800 OneLiveIOS[3323:75768] ====================== touchesNSthread END ======================
Program ended with exit code: 0

GCD

GCD,全名Grand Central Dispatch,大中枢派发,是依据C言语的一套多线程开发API,是目前苹果官方推荐的多线程开发办法。总体来说,他处理直接操作线程带来的难题,它主动帮你办理了线程的生命周期以及使命的履行规矩。下面会频繁的说道一个词,那便是使命,说白了,使命其实便是你要履行的那段代码。

使命办理办法——行列

当要办理多个使命时,线程开发给带来了必定的技能难度,或者说不方便性,GCD给出了统一办理使命的办法,那便是行列。看一下iOS多线程操作中的行列:(⚠️不管是串行仍是并行,行列都是依照FIFO的原则依次触发使命)

两个通用行列

  • 串行行列:一切使命会在一条线程中履行(有可能是当时线程也有可能是新拓荒的线程),而且一个使命履行结束后,才开端履行下一个使命。(等候完结)

  • 并行行列:能够敞开多条线程并行履行使命(但不必定会敞开新的线程),而且当一个使命放到指定线程开端履行时,下一个使命就能够开端履行了。(等候产生)

两个特殊行列

  • 主行列:体系创立好的一个串行行列,牛逼之处在于它办理有必要在主线程中履行的使命,归于有劳保的。

  • 全局行列:体系创立好的一个并行行列,运用起来与自己创立的并行行列无本质差别。

使命履行办法

说完行列,相应的,使命除了办理,还得履行。而且在GCD中并不能直接拓荒线程履行使命,所以在使命参加行列之后,GCD给出了两种履行办法——同步履行(sync)异步履行(async)

  • 同步履行:在当时线程履行使命,不会拓荒新的线程。有必要比及Block函数履行结束后,dispatch函数才会回来。

  • 异步履行:能够在新的线程中履行使命,但不必定会拓荒新的线程。dispatch函数会立即回来, 然后Block在后台异步履行。

使命行列组合办法

线程死锁

- (void)touchesDeadLock {
    NSLog(@"touchesDeadLock, 1========%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    });
    NSLog(@"touchesDeadLock, 3========%@",[NSThread currentThread]);
}

【iOS】多线程梳理

剖析一下为什么会死锁 先做一个界说:- (void)touchesDeadLock{} —> 使命A,GCD同步使命 —>使命B。 总而言之呢,大概是这样的,首先,使命A在主行列,而且已经开端履行,在主线程打印出touchesDeadLock, 1===... ...,然后这时使命B被参加到主行列中,而且同步履行,体系说,同步履行啊,那我不开新的线程了,使命B说我要等我里面的Block函数履行完结,要不我就不回来,可是主行列是串行的,得等A履行完才干轮到B,不能坏了规矩,一起,使命B作为使命A的内部函数,有必要等使命B履行完函数回来才干履行下一个使命。那就形成了,使命A等候使命B完结才干持续履行,但作为串行行列的主行列又不能让使命B在使命A未完结之前开端履行所以使命A等着使命B完结使命B等着使命A完结等候永久的等候所以就死锁了

不死锁

- (void)touchesNoDeadLock {
    NSLog(@"touchesNoDeadLock, 1========%@",[NSThread currentThread]);
    NSLog(@"touchesNoDeadLock, 2========%@",[NSThread currentThread]);
    NSLog(@"touchesNoDeadLock, 3========%@",[NSThread currentThread]);
}
2022-08-09 00:08:31.004427+0800 OneLiveIOS[3562:83930] touchesNoDeadLock, 1========<NSThread: 0x100705830>{number = 1, name = main}
2022-08-09 00:08:31.004870+0800 OneLiveIOS[3562:83930] touchesNoDeadLock, 2========<NSThread: 0x100705830>{number = 1, name = main}
2022-08-09 00:08:31.004894+0800 OneLiveIOS[3562:83930] touchesNoDeadLock, 3========<NSThread: 0x100705830>{number = 1, name = main}
Program ended with exit code: 0

其实这里有一个误区,那便是使命在主线程次序履行便是主行列。其实一点联系都没有,假如当时在主线程,同步履行使命,不管在什么行列使命都是次序履行。把一切使命都以异步履行的办法参加到主行列中,你会发现它们也是次序履行的

改一下

- (void)touchesDeadLock {
    NSLog(@"touchesDeadLock, 1========%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    });
    // dispatch_sync(dispatch_get_main_queue(), ^{
    //     NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    // });
    NSLog(@"touchesDeadLock, 3========%@",[NSThread currentThread]);
}
2022-08-09 00:10:08.977420+0800 OneLiveIOS[3598:85028] touchesDeadLock, 1========<NSThread: 0x106005830>{number = 1, name = main}
2022-08-09 00:10:08.977765+0800 OneLiveIOS[3598:85028] touchesDeadLock, 2========<NSThread: 0x106005830>{number = 1, name = main}
2022-08-09 00:10:08.977790+0800 OneLiveIOS[3598:85028] touchesDeadLock, 3========<NSThread: 0x106005830>{number = 1, name = main}
Program ended with exit code: 0

发现正常履行了,而且是次序履行的,和上诉状况一样,使命A在主行列中,可是使命B参加到了全局行列,这时分,使命A和使命B没有行列的束缚,所以使命B就先履行,履行结束之后函数回来,使命A接着履行。

再改一下

- (void)touchesDeadLock {
    NSLog(@"touchesDeadLock, 1========%@",[NSThread currentThread]);
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    });
    // dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //     NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    // });
    // dispatch_sync(dispatch_get_main_queue(), ^{
    //     NSLog(@"touchesDeadLock, 2========%@",[NSThread currentThread]);
    // });
    NSLog(@"touchesDeadLock, 3========%@",[NSThread currentThread]);
}
2022-08-09 00:12:58.484627+0800 OneLiveIOS[3674:87913] touchesDeadLock, 1========<NSThread: 0x10070a5e0>{number = 1, name = main}
2022-08-09 00:12:58.485050+0800 OneLiveIOS[3674:87913] touchesDeadLock, 3========<NSThread: 0x10070a5e0>{number = 1, name = main}
// 阻塞未履行, 2022-08-09 00:12:58.485050+0800 OneLiveIOS[3674:87913] touchesDeadLock, 2========<NSThread: 0x10070a5e0>{number = 1, name = main}
Program ended with exit code: 0

发现不是次序打印了,而且也不会死锁,分明都是加到主行列里了啊,其实当使命A在履行时,使命B参加到了主行列,留意,是异步履行,所以dispatch函数不会比及Block履行完结才回来,dispatch函数回来后,那使命A能够持续履行,Block使命能够以为鄙人一帧次序参加行列,而且默认无限下一帧履行。

行列与履行办法的调配

//串行行列
self.serialQueue = dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL);
//并行行列
self.concurrentQueue = dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT);

1. 串行行列 + 同步履行

- (void)queue_taskTest{
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
- (void)queue_taskTest {
    dispatch_sync(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
2022-08-09 10:58:52.928519+0800 OneLiveIOS[3431:55258] queue_taskTest, 1========<NSThread: 0x1005190a0>{number = 1, name = main}
2022-08-09 10:58:52.929207+0800 OneLiveIOS[3431:55258] queue_taskTest, 2========<NSThread: 0x1005190a0>{number = 1, name = main}
2022-08-09 10:58:52.929232+0800 OneLiveIOS[3431:55258] queue_taskTest, 3========<NSThread: 0x1005190a0>{number = 1, name = main}
2022-08-09 10:58:52.929248+0800 OneLiveIOS[3431:55258] queue_taskTest, 4========<NSThread: 0x1005190a0>{number = 1, name = main}
Program ended with exit code: 0

全部都在当时线程次序履行,也便是说,同步履行不具备拓荒新线程的才干。

2. 串行行列 + 异步履行

- (void)queue_taskTest {
    dispatch_async(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(self.serialQueue, ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
- (void)queue_taskTest_ {
    dispatch_async(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(dispatch_queue_create("serialQueue.ys.com", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
2022-08-09 11:01:10.928031+0800 OneLiveIOS[3512:57482] queue_taskTest, 2========<NSThread: 0x100704080>{number = 4, name = (null)}
2022-08-09 11:01:10.928031+0800 OneLiveIOS[3512:57483] queue_taskTest, 3========<NSThread: 0x100604c00>{number = 3, name = (null)}
2022-08-09 11:01:10.928117+0800 OneLiveIOS[3512:57187] queue_taskTest, 4========<NSThread: 0x10051b730>{number = 1, name = main}
2022-08-09 11:01:10.928060+0800 OneLiveIOS[3512:57481] queue_taskTest, 1========<NSThread: 0x1006044c0>{number = 2, name = (null)}
Program ended with exit code: 0

先打印了2,然后次序在子线程中打印3,4,1。说明异步履行具有拓荒新线程的才干,而且串行行列有必要比及前一个使命履行完才干开端履行下一个使命,一起,异步履行会使内部函数首先回来,不会与正在履行的外部函数产生死锁。

并行行列 + 同步履行

- (void)queue_taskTest {
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
- (void)queue_taskTest__ {
    dispatch_sync(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_sync(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_sync(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
2022-08-09 11:03:19.053886+0800 OneLiveIOS[3570:59273] queue_taskTest, 1========<NSThread: 0x100705830>{number = 1, name = main}
2022-08-09 11:03:19.054185+0800 OneLiveIOS[3570:59273] queue_taskTest, 2========<NSThread: 0x100705830>{number = 1, name = main}
2022-08-09 11:03:19.054234+0800 OneLiveIOS[3570:59273] queue_taskTest, 3========<NSThread: 0x100705830>{number = 1, name = main}
2022-08-09 11:03:19.054257+0800 OneLiveIOS[3570:59273] queue_taskTest, 4========<NSThread: 0x100705830>{number = 1, name = main}
Program ended with exit code: 0

未敞开新的线程履行使命,而且Block函数履行完结后dispatch函数才会回来,才干持续向下履行,所以看到的结果是次序打印的。

4. 并行行列 + 异步履行

- (void)queue_taskTest {
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(self.concurrentQueue, ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
- (void)queue_taskTest___ {
    dispatch_async(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 1========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:1];
    });
    dispatch_async(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 2========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:2];
    });
    dispatch_async(dispatch_queue_create("concurrentQueue.ys.com", DISPATCH_QUEUE_CONCURRENT), ^{
        NSLog(@"queue_taskTest, 3========%@",[NSThread currentThread]);
        //[self nslogCount:10000 number:3];
    });
    NSLog(@"queue_taskTest, 4========%@",[NSThread currentThread]);
}
2022-08-09 11:04:32.532527+0800 OneLiveIOS[3606:60355] queue_taskTest, 2========<NSThread: 0x10050d640>{number = 3, name = (null)}
2022-08-09 11:04:32.532530+0800 OneLiveIOS[3606:60356] queue_taskTest, 3========<NSThread: 0x10050d740>{number = 4, name = (null)}
2022-08-09 11:04:32.532638+0800 OneLiveIOS[3606:60354] queue_taskTest, 1========<NSThread: 0x10060af80>{number = 2, name = (null)}
2022-08-09 11:04:32.532705+0800 OneLiveIOS[3606:60115] queue_taskTest, 4========<NSThread: 0x100707080>{number = 1, name = main}
Program ended with exit code: 0

拓荒了多个线程,触发使命的时机是次序的,可是看到完结使命的时刻却是随机的,这取决于CPU关于不同线程的调度分配,可是,线程不是无条件无限拓荒的,当使命量足够大时,线程是会重复利用的。

总结

  1. 关于单核CPU来说,不存在真实含义上的并行,所以,多线程履行使命,其实也只是一个人在干活,CPU的调度决议了非等候使命的履行速率,一起关于非等候使命,多线程并没有真实含义提高功率

  2. 线程能够简单的以为便是一段代码+运行时数据。

  3. 同步履行会在当时线程履行使命,不具备拓荒线程的才干或者说没有必要拓荒新的线程。而且,同步履行有必要比及Block函数履行结束,dispatch函数才会回来,从而阻塞同一串行行列中外部办法的履行。

  4. 异步履行dispatch函数会直接回来,Block函数能够以为它会鄙人一帧参加行列,并依据地点行列目前的使命状况无限下一帧履行,从而不会阻塞当时外部使命的履行。一起,只要异步履行才有拓荒新线程的必要,可是异步履行不必定会拓荒新线程。

  5. 只要是行列,必定是FIFO(先进先出),可是谁先履行完要看第1条。

  6. 只要是串行行列,必定要等上一个使命履行完结,才干开端下一个使命。可是并行行列当上一个使命开端履行后,下一个使命就能够开端履行。

  7. 想要拓荒新线程有必要让使命在异步履行,想要拓荒多个线程,只要让使命在并行行列中异步履行才干够。履行办法和行列类型多层组合在必定程度上能够实现关于代码履行次序的调度。

  8. 同步+串行:未拓荒新线程,串行履行使命;同步+并行:未拓荒新线程,串行履行使命;异步+串行:新拓荒一条线程,串行履行使命;异步+并行:拓荒多条新线程,并行履行使命;在主线程中同步运用主行列履行使命,会形成死锁。

  9. 关于多核CPU来说,线程数量也不能无限拓荒,线程的拓荒同样会耗费资源,过多线程一起处理使命并不是幻想中的人多力量大。

比方

使命的办理办法——行列,串行行列和并行行列就像是人以什么规矩打电话,排队一个等一个去,仍是抢着去;

使命的履行办法——同步或异步履行,就像供给当时一个电话机,仍是能够请求新的电话机。 而多线程的运作就等于是这些人去打电话。 同步履行的时分不能拓荒新的线程,异步履行的时分能够拓荒新的线程,但不必定拓荒。