操作系统中正在运行的一个应用程序都会有一个独立的进程,每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内。一个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程),线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行。一个进程内可以有多个线程,这些线程作为操作系统调度的最小单元,负责执行各种各样的任务,这些线程都拥有各自的计数器、堆栈、局部变量等属性,并且可以访问共享内存,在一个线程内顺序的执行CUP无分叉的命令列。
当前常见的编程语言开发的程序,开发语言只是为了使程序员更好的操作,实质上,对计算机而言,程序会转换成其能理解的汇编语言进而解释成机器码来执行。机器码是按顺序执行的,一个复杂的多步操作只能一步步按顺序逐个执行。因此才有了多线程和多核CPU等技术的使用。
对于单核处理器,可以将多个步骤放到不同的线程,这样一来用户完成UI操作后其他后续任务在其他线程中,当CPU空闲时会继续执行,而此时对于用户而言可以继续进行其他操作。
对于多核处理器,如果用户在UI线程中完成某个操作之后,其他后续操作在别的线程中继续执行,用户同样可以继续进行其他UI操作,与此同时前一个操作的后续任务可以分散到多个空闲CPU中继续执行(当然具体调度顺序要根据程序设计而定),既解决了线程阻塞又提高了运行效率。苹果从双核A5处理器后又在A7中加入了协处理器,优化性能不只是在多线程,还有处理器的性能。
并发是一种现象,一种经常出现,无可避免的现象。它描述的是“多个任务同时发生,需要被处理”这一现象。它的侧重点在于“发生”。并行指的是一种技术,一个同时处理多个任务的技术。它描述了一种能够同时处理多个任务的能力,侧重点在于“运行”。并行的反义词就是串行,表示任务必须按顺序来,一个一个执行,前一个执行完了才能执行后一个。多线程,正是采用了并行技术,从而提高了执行效率。因为有多个线程,所以计算机的多个CPU可以同时工作,同时处理不同线程内的指令。创建多个线程,真正加快程序运行速度的,是并行技术。也就是让多个CPU同时工作。
在低层,GCD全局dispatch queue仅仅是工作线程池的抽象。这些队列中的Block一旦可用,就会被dispatch到工作线程中。提交至用户队列的Block最终也会通过全局队列进入相同的工作线程池(除非你的用户队列的目标是主线程,但是为了提高运行速度,我们绝不会这么干)。有两种途径来通过GCD“榨取”多核心系统的性能:将单一任务或者一组相关任务并发至全局队列中运算;将多个不相关的任务或者关联不紧密的任务并发至用户队列中运算。
线程 start 后操作系统会给他分配相关的资源,包括单独的程序计数器和栈。操作系统会把这个线程作为一个独立的个体进行调度,分配时间片让它执行。线程被 CPU 调度后就会执行线程中的方法。
以NSThread为例:
@interface ViewController ()
@property (nonatomic, strong) NSThread *thread;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建线程
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil];
//设置线程的名称
[thread setName:@"线程A"];
self.thread = thread;
}
//当手指按下的时候,开启线程
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//开启线程
[self.thread start];
}
-(void)test
{
//获取线程
NSThread *current=[NSThread currentThread];
NSLog(@"test---打印线程---%@",self.thread.name);
NSLog(@"test---线程开始---%@",current.name);
//设置线程阻塞,阻塞秒
NSLog(@"接下来,线程阻塞0.5秒");
[NSThread sleepForTimeInterval:.5];
//第二种设置线程阻塞,以当前时间为基准阻塞秒
NSLog(@"接下来,线程阻塞0.5秒");
NSDate *date=[NSDate dateWithTimeIntervalSinceNow:.5];
[NSThread sleepUntilDate:date];
for (int i= 0; i<10; i++) {
NSLog(@"线程--%d--%@",i,current.name);
if (9==i) {
//结束线程 (线程死了不能复生,如果在线程死亡之后,再次点击屏幕尝试重新开启线程,则程序会挂)
[NSThread exit];
}
}
NSLog(@"test---线程结束---%@",current.name);
}
@end
sleep方法使当前所在线程进入阻塞,只是让出 CPU ,并没有释放对象锁。由于休眠时间结束后不一定会立即被 CPU 调度,因此线程休眠的时间可能大于传入参数。