专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
51好读  ›  专栏  ›  Cocoa开发者社区

并发编程槽与坑

Cocoa开发者社区  · 公众号  · ios  · 2017-05-08 17:03

正文

何为并发 何为多线程

操作系统中正在运行的一个应用程序都会有一个独立的进程,每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内。一个进程要想执行任务,必须得有线程(每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 调度,因此线程休眠的时间可能大于传入参数。

多线程中的内存析构






请到「今天看啥」查看全文