Concurrency Programming Guide 2 Concurrency and Application Design
Concurrency and Application Design
关于iOS多线程先看这个:
一.线程概述
有些程序是一条直线,起点到终点;有些程序是一个圆,不断循环,直到将它切断。直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样;圆如操作系统,一直运行直到你关机。
一个运行着的程序就是一个进程或者叫做一个任务,一个进程至少包含一个线程,线程就是程序的执行流。Mac和iOS中的程序启动,创建好一个进程的同时,一个线程便开始运行,这个线程叫主线程。主线程在程序中的地位和其他线程不同,它是其他线程最终的父线程,且所有界面的显示操作即AppKit或UIKit的操作必须在主线程进行。
系统中的每一个进程都有自己独立的虚拟内存空间,而同一个进程中的多个线程则共用进程的内存空间。每创建一个新的线程,都需要一些内存(如每个线程有自己的Stack空间)和消耗一定的CPU时间。另外当多个线程对同一个资源出现争夺的时候需要注意线程安全问题。
二.创建线程
创建一个新的线程就是给进程增加了一个执行流,执行流总得有要执行的代码吧,所以新建一个线程需要提供一个函数或者方法作为线程的入口。
1. 使用NSThread
NSThread提供了创建线程的途径,还可以提供了检测当前线程是否是主线程的方法。 使用NSThread创建一个新的线程有两种方式:
- 创建一个NSThread的对象,调用其
start
方法。对于这种方式的NSThread对象的创建,可以使用一个目标对象的方法初始化一个NSThread对象,或者创建一个继承NSThread类的子类,实现其main方法,然后在直接创建这个子类的对象。- 使用
detachNewThreadSelector:toTarget:withObject:
这个类方法创建一个线程,这个比较直接了,直接使用目标对象的方法作为线程启动入口。
2. 使用NSObject
其实NSObject直接就加入了多线程的支持,允许对象的某个方法在后台运行。如:
[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];
3.POSIX Thread
由于Mac和iOS都是基于Darwin系统,Darwin系统的XUN内核,是基于Mach和BSD的,继承了BSD的POSIX接口,所以可以直接使用POSIX线程的相关接口来使用线程。
比起手动创建/管理线程,我们更加希望:
- 充分利用多核CPU性能
- 应用程序应该根据系统当前负载动态地创建线程/使用CPU资源
- 简化多线程编程难度
而Apple提供的Operation queue
和Dispatch queue(GCD)
正是为这些问题提供了解决方案。
Asynchronous design approach
异步设计方法
关于程序并发,OS X和iOS使用了asynchronous design approach。Asynchronous函数会创建新的线程(一般情况下)来执行代码,不管代码是否执行万,它会马上返回一个通知给主线程(这里主线程是指调用Asynchronous函数的线程)。
Dispatch queue
Dispatch queue由GCD提供,而 GCD 是基于 C 的 API 。实现了并行和串行线程队列。执行顺序总是先进先出。
提交到dispatch queue的任务可以是一个function或者block。
什么是 GCD
GCD 是 libdispatch 的市场名称,而 libdispatch 作为 Apple 的一个库,为并发代码在多核硬件(跑 iOS 或 OS X )上执行提供有力支持。它具有以下优点:
- GCD 能通过推迟昂贵计算任务并在后台运行它们来改善你的应用的响应性能。
- GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱。
- GCD 具有在常见模式(例如单例)上用更高性能的原语优化你的代码的潜在能力。
Dispatch source1
GCD 的一个特别有趣的特性是 Dispatch Source,它基本上就是一个低级函数的 grab-bag ,能帮助你去响应或监测 Unix 信号、文件描述符、Mach 端口、VFS 节点,以及其它晦涩的东西。所有这些都超出了本教程讨论的范围,但你可以通过实现一个 Dispatch Source 对象并以一个相当奇特的方式来使用它来品尝那些晦涩的东西。
第一次使用 Dispatch Source 可能会迷失在如何使用一个源,所以你需要知晓的第一件事是 dispatch_source_create 如何工作。下面是创建一个源的函数原型:
dispatch_source_t dispatch_source_create(
dispatch_source_type_t type,
uintptr_t handle,
unsigned long mask,
dispatch_queue_t queue);
第一个参数是 dispatch_source_type_t 。这是最重要的参数,因为它决定了 handle 和 mask 参数将会是什么。你可以查看 Xcode 文档 得到哪些选项可用于每个 dispatch_source_type_t 参数。
Operation Queue
Operation Queue和Queue是建立在 GCD 之上的并发技术。大体来说,如果你在写简单的用过就忘的任务,那它们就是使用 GCD 的最佳实践。NSOperations 提供更好的控制、处理大量并发操作的实现,以及一个以速度为代价的更加面向对象的范例。
- 除了先进先出执行任务,Operation Queue还能实现一个任务只能在指定的任务完成之后才能执行。即使这些需要先完成的任务不在同一个Operation Queue都木有问题;
- KVO通知,用来检测任务的执行状态;
关于提高执行效率
- 考虑在任务内完成计算
- 尽量把大量重复的串行任务并行
- 避免使用锁机制
- 除非你有特别的原因要往下流走(译者的玩笑:即使用低级别 API),否则永远应尝试并坚持使用高级的 API。如果你想学到更多或想做某些非常非常“有趣”的事情,那你就应该冒险进入 Apple 的黑暗艺术。