Serial vs. Concurrent 串行 vs. 并发
这些术语描述当任务相对于其它任务被执行,任务串行执行就是每次只有一个任务被执行,任务并发执行就是在同一时间可以有多个任务被执行。
Synchronous vs. Asynchronous 同步 vs. 异步
在 GCD 中,这些术语描述当一个函数相对于另一个任务完成,此任务是该函数要求 GCD 执行的。一个同步函数只在完成了它预定的任务后才返回。
一个异步函数,刚好相反,会立即返回,预定的任务会完成但不会等它完成。因此,一个异步函数不会阻塞当前线程去执行下一个函数。
Deadlock 死锁
两个(有时更多)东西——在大多数情况下,是线程——所谓的死锁是指它们都卡住了,并等待对方完成或执行其它操作。第一个不能完成是因为它在等待第二个的完成。但第二个也不能完成,因为它在等待第一个的完成。
(https://github.com/nixzhu/dev-blog/blob/master/2014-04-19-grand-central-dispatch-in-depth-part-1.md#thread-safe-线程安全)Thread Safe 线程安全
线程安全的代码能在多线程或并发任务中被安全的调用,而不会导致任何问题(数据损坏,崩溃,等)。线程不安全的代码在某个时刻只能在一个上下文中运行。一个线程安全代码的例子是 NSDictionary
。你可以在同一时间在多个线程中使用它而不会有问题。另一方面,NSMutableDictionary
就不是线程安全的,应该保证一次只能有一个线程访问它。
Queues 队列
GCD 提供有 dispatch queues
来处理代码块,这些队列管理你提供给 GCD 的任务并用 FIFO 顺序执行这些任务。这就保证了第一个被添加到队列里的任务会是队列中第一个开始的任务,而第二个被添加的任务将第二个开始,如此直到队列的终点。
所有的调度队列(dispatch queues)自身都是线程安全的,你能从多个线程并行的访问它们。当你了解了调度队列如何为你自己代码的不同部分提供线程安全后,GCD的优点就是显而易见的。关于这一点的关键是选择正确类型的调度队列和正确的调度函数来提交你的工作。
在本节你会看到两种调度队列,都是由 GCD 提供的,然后看一些描述如何用调度函数添加工作到队列的例子。
[
](https://github.com/nixzhu/dev-blog/blob/master/2014-04-19-grand-central-dispatch-in-depth-part-1.md#serial-queues-串行队列)Serial Queues 串行队列
串行队列中的任务一次执行一个,每个任务只在前一个任务完成时才开始。而且,你不知道在一个 Block 结束和下一个开始之间的时间长度,如下图所示:
同步:不会开启新的线程,在本线程中执行,异步:具有开启子线程的能力,但是会不会开启就要看自己加的那个队列了,如果队列是主队列,就不会创建子线程,所有的任务会在主队列中完成,如果是异步,且在全局队列中会首先创建一个子线程,每一个block里的代码,就是一个任务,将每一个任务加载到一个队列中,这个队列是全局队列的话,并且是异步的话,会产生多个子线程,全局队列就是并发的意思,队列有一个先进先出的特点,当自己有一个在主线程中执行的任务的时候,如果eg:
[sef creatsyncQueue]//主线程执行
+(void)creatsyncQueue
[
dispatch_sync(get_main_queue()){
nslog(“”);//死锁乐
}
将sync换成async不会死锁,因为这时候async不会先执行里边的代码
}
步骤: 1 创建队列 2 创建任务 3 将任务加到队列中,同步还是异步
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下载图片
UIImage *image = nil;
1 dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程
//在这使用主队列会将在主线程中执行,为啥使用异步呢?
});
下面是一个关于在 dispatch_async 上如何以及何时使用不同的队列类型的快速指导:
自定义串行队列:当你想串行执行后台任务并追踪它时就是一个好选择。这消除了资源争用,因为你知道一次只有一个任务在执行。注意若你需要来自某个方法的数据,你必须内联另一个 Block 来找回它或考虑使用 dispatch_sync。
主队列(串行):这是在一个并发队列上完成任务后更新 UI 的共同选择。要这样做,你将在一个 Block 内部编写另一个 Block 。以及,如果你在主队列调用 dispatch_async 到主队列,你能确保这个新任务将在当前方法完成后的某个时间执行。
并发队列:这是在后台执行非 UI 工作的共同选择。
单例:
- (instancetype)sharedManager
{
static PhotoManager *sharedPhotoManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPhotoManager = [[PhotoManager alloc] init];
sharedPhotoManager->_photosArray = [NSMutableArray array];
});
return sharedPhotoManager;
}