Multithreading in iOS

进程和线程

进程是指正在运行的一个应用程序实例。每个进程都是独立的,运行在受保护的内存空间里面。
一个进程想执行任务,必须要至少有一个线程。线程是进程的基本执行单元。

多线程

一个进程里开启多条线程,每条线程并发执行不同的任务。多线程可以提高程序的运行效率。

原理

同一时间,CPU 只能处理一条线程,多线程是 CPU 不停地各个线程间切换造成的假象。

优缺点

优点:
  • 提高程序的执行效率
  • 提高资源的利用率(CPU,内存利用率)
缺点:
  • 开启线程需要占用内存空间,开启大量线程会降低程序的性能
  • 线程越多,CPU 在线程切换的开销越大
  • 程序设计更加复杂(线程间通信)

多线程在 iOS 开发中的应用

主线程

程序运行后,默认会开启一条线程(UI 线程)。
作用是,显示、刷新 UI 界面,处理 UI 事件。
不要将比较耗时的操作放到主线程中。

多线程实现方案

notion image

使用 NSThread

  • 一个 NSThread 对象就代表一条线程
  • 线程函数结束以后就代表线程生命周期终结,不能再次启动线程,而是得创建新的线程
// 创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadFunction) object:nil];

// 启动线程
[thread start];

GCD

GCD 的全称是 Grand Central Dispatch,对于这种专业词汇就不要翻译成「大神经中枢派发」了,就了解它是一种多线程技术就好了。 GCD 有两个关键概念: GCD 的使用就是创建任务,接着把任务添加到队列就好了。 #### 任务 执行的操作
// 使用同步的方式执行,在当前线程执行
void dispatch_sync ( dispatch_queue_t queue, dispatch_block_t block );
// 异步
void dispatch_async ( dispatch_queue_t queue, dispatch_block_t block );

队列

用来存放任务 - 串行队列:这个队列的所有任务都是按顺序进行的 - 并发队列:所有任务都是同时进行的,线程的创建交由操作系统进行 - 获得全局并发队列:dispatch_queue_t dispatch_get_global_queue ( long identifier, unsigned long flags );

GCD 中的几个函数

// 延时执行
dispatch_after
// 只执行一次
dispatch_once

GCD 中的队列组

队列组是把任务都放进一个组里,当组里所有的任务都被处理完毕以后,会通知
// 创建组
dispatch_group_t group = dispatch_group_create();
// 获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 进行耗时操作
dispatch_group_async(group, queue, ^{

});
// 进行耗时操作
dispatch_group_async(group, queue, ^{

});
// 前两个任务都结束以后,会调用这个 block
dispatch_group_notify(group, queue, ^{

});

多线程的安全隐患

多个线程访问同一块资源(对象,变量,文件等)。 ### 互斥锁
@synchronized(self) {
      // 加锁区域
     // 小括号里面放的是锁的对象,通常传 self 就可以(代表同一把锁)
}
优点: - 能解决线程安全问题 缺点: - 消耗大量 CPU 资源 ## 线程间的通信 在一个线程执行下载内容,但是需要把下载好的东西更新到 UI 上,这时候需要在线程之间传递东西。 不可以在子线程执行更新 UI 的操作,因为主线程也会对 UI 操作,这样会发生问题的。
// 回到主线程操作,是 NSObject 的方法,任意控件都可以执行这种操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

// 使用 GCD,在子线程的 BLOCK 中,再调用 dispatch_async 回到主线程更新 UI

© Xinyu 2014 - 2024