什么是多线程
实现多个线程并发执行的技术叫做多线程。我们可以将一些耗时的操作放在子线程中,这样大大提高了我们应用程序的响应性能,但也带来了不少风险,主要的有下面3种风险:
- 数据竞争:多个线程更新相同的资源会导致数据的不一致。
- 死锁:停止等待事件的线程会导致多个线程相互持续等待。
-
大量消耗内存:使用太多线程会消耗大量内存。
多线程不安全性图示
下面在讲GCD的过程中会提到这些问题,请往下看。
什么是GCD
Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可执行任务,这样就比以前的线程更有效率。
GCD的API
Dispatch Queue
GCD在执行处理中存在两种Dispatch Queue:
Dispatch Queue种类 | 说明 |
---|---|
Serial Dispatch Queue | 串行队列,等待现在执行中处理结束 |
Concurrent Dispatch Queue | 并行队列,不等待处理结束 |
dispatch_queue_create
dispatch_queue_create函数的第一个参数指定的是Dispatch Queue的名称,推荐使用应用程序ID这种逆序全程域名(FQDN,full qualified domain name)。第二个参数是指定队列种类,比如生成Serial Dispatch Queue(串行队列)时,传“NULL”或者“DISPATCH_QUEUE_SERIAL”;而生成Concurrent Dispatch Queue(并行队列)时,传“DISPATCH_QUEUE_CONCURRENT”。
//串行队列
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.zjb.gcd.mySerialQueue", NULL);
//并行队列
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.zjb.gcd.myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
这里需要讲一下串行队列生成个数的注意事项。并行队列能并行执行多个追加处理,而串行队列同时只能执行1个追加处理。虽然串行队列和并行队列都受到系统资源的限制,但用dispatch_queue_create函数可以生成任意多个串行队列。
当生成多个串行队列时,各个串行队列讲并行执行,每一个串行队列,系统就对应生成一个线程这就造成了,文章开头说的三个风险中的线程过多,大量消耗内存的问题。但是串行队列能有效的避免另一个问题,那就是数据竞争问题。
那有人会问,那并行队列怎么不会出现这样的问题?
因为iOS和OS X的核心 —— XNU内核的有效管理。XNU内核将会决定应当使用的线程数,并只生成所需的线程执行处理;并且在处理结束,应当执行的处理数减少时,XNU内核会结束不再需要的线程。举个例子:
线程0 | 线程1 | 线程2 | 线程3 |
---|---|---|---|
blk0 | blk1 | blk2 | blk3 |
blk4 | blk6 | blk5 | |
blk7 |
假设准备4个并行队列用线程。首先blk0在线程0中开始执行,接着blk1在线程1中、blk2在线程2中、blk3在线程3中开始执行。线程0中blk0执行结束后开始执行blk4,由于线程1中blk1的执行没有结束,因此线程2中blk2执行结束后开始执行blk5,就这样循环往复。像这样合理的管理着线程。
Main Dispatch Queue/Global Dispatch Queue
系统标准提供给我们了两个Dispatch Queue,一个是Main Dispatch Queue,另一个是Global Dispatch Queue。
Main Dispatch Queue,是在主线程中执行的Dispatch Queue,它是串行队列。追加到Main Dispatch Queue的处理在主线程的RunLoop中执行。由于在主线程中执行,因此要将用户界面的界面更新等一些必须在主线程中执行的处理追加到Main Dispatch Queue使用。
Global Dispatch Queue,是所有应用程序都能够使用的串行队列。没有必要通过dispatch_queue_create函数逐个生成串行队列。只要获取Global Dispatch Queue使用即可。
另外,Global Dispatch Queue有4个执行优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(Low Priority)和后台优先级(Background Priority)。
//Main Dispatch Queue的获取方法
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
//Global Dispatch Queue(高优先级)的获取方法
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//Global Dispatch Queue(默认优先级)的获取方法
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//Global Dispatch Queue(低优先级)的获取方法
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//Global Dispatch Queue(后台优先级)的获取方法
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
以下列举一下使用Main Dispatch Queue和Global Dispatch Queue的代码:
//在默认优先级的Global Dispatch Queue中执行Block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//可并行执行的处理
//在Main Dispatch Queue中执行Block
dispatch_async(dispatch_get_main_queue(), ^{
//只能在主线程中执行的处理
});
});
网友评论