iOS开发资料收集区ios专题iOS面试汇总

可能碰到的iOS笔试面试题(18)--多线程

2016-05-04  本文已影响10057人  b485c88ab697

多线程

你们项目中为什么多线程用GCD而不用NSOperation呢? 你有没有发现国外的大牛他们多线程都是用NSOperation? 你能告诉我他们这样做的理由吗?

关系:

①:先搞清两者的关系,NSOpertaionQueue用GCD构建封装的,是GCD的高级抽象!

②:GCD仅仅支持FIFO队列,而NSOperationQueue中的队列可以被重新设置优先级,从而实现不同操作的执行顺序调整。GCD不支持异步操作之间的依赖关系设置。如果某个操作的依赖另一个操作的数据(生产者-消费者模型是其中之一),使用NSOperationQueue能够按照正确的顺序执行操作。GCD则没有内建的依赖关系支持。

③:NSOperationQueue支持KVO,意味着我们可以观察任务的执行状态。

了解以上不同,我们可以从以下角度来回答

性能:①:GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。这取决于使用Instruments进行代码性能分析,如有必要的话

②:从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持

③:如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势

最后的一句话:别忘了高德纳的教诲:“在大概97%的时间里,我们应该忘记微小的性能提升。过早优化是万恶之源。”只有Instruments显示有真正的性能提升时才有必要用低级的GCD。

详解GCD死锁

unix上进程怎么通信?

列举几种进程的同步机制、进程的通信途径、死锁及死锁的处理方法。

线程与进程的区别和联系?

iOS线程间怎么通信?

iOS多线程的底层实现?

谈谈多线程安全问题的几种解决方案?何为线程同步,如何实现的?分线程回调主线程方法是什么,有什么作用?

使用atomic一定是线程安全的吗?

不是的。 
atomic原子操作,系统会为setter方法加锁。 具体使用 @synchronized(self){//code } 
nonatomic不会为setter方法加锁。 
atomic:线程安全,需要消耗大量系统资源来为属性加锁 
nonatomic:非线程安全,适合内存较小的移动设备
使用atomic并不能保证绝对的线程安全,对于要绝对保证线程安全的操作,还需要使用更高级的方式来处理,比如NSSpinLock、@syncronized等

谈谈你对多线程开发的理解(多线程的好处,多线程的作用)?ios中有几种实现多线程的方法?

OC中异步使用的哪种事件模型,iOS中异步实现机制

详细谈谈GCD

  1. 推出的时间 iOS4 目的是用来取代NSThread(ios2.0推出)的,是 C语言框架,它能够自动利用更多CPU的核数,并且会自动管理线程的生命周期。

    • CGD的两个核心概念:任务, 队列
    • 任务:记为在block中执行的代码。
    • 队列:用来存放任务的。
    • 注意事项: 队列 != 线程。队列中存放的任务最后都要由线程来执行!。队列的原则:先进先出,后进后出(FIFO/ First In First Out)
  2. 队列又分为四种种:1 串行队列 2 并发队列 3 主队列 4 全局队列

    • 串行队列: 任务一个接一个的执行。
    • 并发队列: 队列中的任务并发执行。
    • 主队列: 跟主线程相关的队列,主队列里面的内容都会在主线程中执行(我们一般在主线程中刷新UI)。
    • 全局队列: 一个特殊的并发队列。
  3. 并发队列与全局队列的区别:

    • 并发队列有名称,可以跟踪错误。全局队列没有
    • 在ARC中两个队列不需要考虑释放内存,但是在MRC中并发队列是创建出来的需要release操作,而全局队列只有一个不需要。
    • 一般在开发过程中我们使用全局队列。
  1. 执行任务的两个函数

    • '同步'执行任务:dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
    • '异步'执行任务:dispatch_async(dispatch_queue_t queue, <#^(void)block#>)
  2. "同步"和"异步"的区别:

    • "同步": 只能在'当前'线程中执行任务,不具备开启新线程的能力.
    • "异步": 可以在'新'的线程中执行任务,具备开启新线程的能力.
  3. 各个队列的执行效果:

    • 串行队列同步执行,既在当前线程中顺序执行
    • 串行队列异步执行,开辟一条新的线程,在该线程中顺序执行
    • 并行队列同步执行,不开辟线程,在当前线程中顺序执行
    • 并行队列异步执行,开辟多个新的线程,并且线程会重用,无序执行
    • 主队列异步执行,不开辟新的线程,顺序执行
    • 主队列同步执行,会造成死锁('主线程'和'主队列'相互等待,卡住主线程)
  4. 线程间通讯:经典案例:子线程进行耗时操作(例如下载更新等)主线程进行UI刷新。

    • 经典用法(子线程下载(耗时操作),主线程刷新UI):
dispatch_async(dispatch_get_global_queue(0, 0), ^{ 

 // 执行耗时的异步操作...

dispatch_async(dispatch_get_main_queue(), ^{

// 回到主线程,执行UI刷新操作
  1. 延迟操作

    调用 NSObject 方法:[self performSelector:@selector(run) withObject:nil afterDelay:2.0];

    // 2秒后再调用self的run方法

    GCD函数实现延时执行:dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

    // 2秒后执行这里的代码... 在哪个线程执行,跟队列类型有关

  1. 队列组的使用:

    • 项目需求:首先:分别异步执行两个耗时操作;其次:等两次耗时操作都执行完毕后,再回到主线程执行操作.使用队列组(dispatch_group_t)快速,高效的实现上述需求.

    dispatch_group_t group = dispatch_group_create(); // 队列组

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 全局并发队列

    dispatch_group_async(group, queue, ^{// 异步执行操作1

    // longTime1

    });

    dispatch_group_async(group, queue, ^{ // 异步执行操作2

    // longTime2

    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

    // 在主线程刷新数据
    // reload Data
    });

GCD内部怎么实现的

GCD的queue、main queue中执行的代码一定是在main thread么?

•   对于queue中所执行的代码不一定在main thread中。如果queue是在主线程中创建的,那么所执行的代码就是在主线程中执行。如果是在子线程中创建的,那么就不会在main thread中执行。
•   对于main queue就是在主线程中的,因此一定会在主线程中执行。获取main queue就可以了,不需要我们创建,获取方式通过调用方法dispatchgetmain_queue来获取。

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 合并图片
});

有a、b、c、d 4个异步请求,如何判断a、b、c、d都完成执行?如果需要a、b、c、d顺序执行,该如何实现?

1.  对于这四个异步请求,要判断都执行完成最简单的方式就是通过GCD的group来实现:
2.  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3.  dispatch_group_t group = dispatch_group_create();
4.  dispatch_group_async(group, queue, ^{ /*任务a */ });
5.  dispatch_group_async(group, queue, ^{ /*任务b */ });
6.  dispatch_group_async(group, queue, ^{ /*任务c */ }); 
7.  dispatch_group_async(group, queue, ^{ /*任务d */ }); 
8.   
9.  dispatch_group_notify(group, dispatch_get_main_queue(), ^{
10.     // 在a、b、c、d异步执行完成后,会回调这里
11. });
当然,我们还可以使用非常老套的方法来处理,通过四个变量来标识a、b、c、d四个任务是否完成,然后在runloop中让其等待,当完成时才退出run loop。但是这样做会让后面的代码得不到执行,直到Run loop执行完毕。
要求顺序执行,那么可以将任务放到串行队列中,自然就是按顺序来异步执行了

发送10个网络请求,然后再接收到所有回应之后执行后续操作,如何实现?

从题目分析可知,10个请求要全部完成后,才执行某一功能。比如,下载10图片后合成一张大图,就需要异步全部下载完成后,才能合并成大图。
做法:通过dispatch_group_t来实现,将每个请求放入到Group中,将合并成大图的操作放在dispatch_group_notify中实现。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); 
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 合并图片
});

苹果为什么要废弃dispatch_get_current_queue?

如果让你来实现 dispatch_once,你会怎么做?

关于NSOperation:

NSOperation queue?

NSOperation与GCD的区别

GCD与NSThread的区别

为什么要取消/恢复队列呢?

Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?

线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;

NSThread创建线程的三种方法:
 NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"nil"];
 [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分离出来的子线程"];
[self performSelectorInBackground:@selector(run:) withObject:@"我是后台线程"];

在主线程执行代码,就调用performSelectorOnMainThread方法。

如果想延时执行代码可以调用performSelector:onThread:withObject:waitUntilDone:方法;

GCD:
利用异步函数dispatch_async()创建子线程。

在主线程执行代码,dispatch_async(dispatch_get_main_queue(), ^{});

延迟执行代码(延迟·可以控制代码在哪个线程执行):
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{});

NSOperationQueue:
使用NSOperation的子类封装操作,再将操作添加到NSOperationQueue创建的队列中,实现多线程。
在主线程执行代码,只要将封装代码的NSOperation对象添加到主队列就可以了。

下面关于线程管理错误的是

A. GCD所用的开销要比NSThread大
B. 可以在子线程中修改UI元素
C. NSOperationQueue是比NSthread更高层的封装
D. GCD可以根据不同优先级分配线程

文章如有问题,请留言,我将及时更正。

满地打滚卖萌求赞,如果本文帮助到你,轻点下方的红心,给作者君增加更新的动力。

上一篇下一篇

猜你喜欢

热点阅读