美文网首页
iOS 多线程

iOS 多线程

作者: iOS资深入门 | 来源:发表于2020-07-05 23:15 被阅读0次

什么是多线程?

同一时间内单核的CPU只能执行一个线程,多线程是CPU快速的在多个线程之前进行切换(调度),造成了多个线程同时执行的假象。
如果是多核CPU就真的可以同时处理多个线程了。
多线程目的是为了同步完成多项任务,通过提高系统的资源利用率来提高系统的效率。
开启线程需要消耗内存资源和性能。每一个纯种都需要分配系统内核空间和程序的内存空间。

线程和进程

进程是一个正在运行的应用程序,一个应用程序对应一个进程。应用程序是一个没有生命的实体,只有运行以后,才能称为一个活动的实体,也就是进程。
进程是操作系统分配资源的基本单元。进程在运行的过程中拥有独立的内在单元,一个进程崩溃后,不会对其他进程造成影响。
线程是独立运行和独立调度的基本单位。线程才是程序真正的执行单元负责代码的执行。一个进程可以有一个或多个线程,同一个进程的线程共享进程的内在资源。线程没有单独的地址空间,一个线程崩溃整个进程就会崩溃。

  • 任务和队列
    任务:执行操作
    队列:用来存放任务

  • 并行和并发
    并行:充分利用计算机的多核,在多个纯种上同步进行
    并发:在一条线程上通过快速切换,让人感觉在同步进行

  • 同步和异步
    同步:只能在当前线程中执行任务,会阻塞当前线程,不具备开启新线程的能力。
    异步:可以在新纯种中执行任务, 开启新纯种的能力。

  • 主线程特点
    主线程会先执行主线程上的代码片段,然后才会去执行放在主队列中的任务。

iOS中多线程的几种方案

  • Pthread是用C语言实现的,非常底层,在开发中很少用到。需要手动管理线程的生命周期(手动创建和销毁)。
  • NSThread面向对象的,需要手动创建纯种,不需要手动销毁。子线程间通信很难。
    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(testWithObject:) object:@"test"];//有反回值,可以设置线程的优先级和名称
    [thread start];//需要开启

    [NSThread detachNewThreadSelector:@selector(testWithObject:) toTarget:self withObject:@"参数"];//没有返回值,自动开启

  • GCD C语言,充分利用了设备的多核,自动管理线程生命周期。比NSOperation效率更高。
    dispatch_sync会阻塞当前纯种,task不执行完毕,dispatch_sync函数不返回。
    dispatch_async不会阻塞当前线程,不等待task执行,直接执行后面的代码。
  • NSOperation 基于gcd封装,更加面向对象,比gcd多了一些功能
    可添加完成的代码块,在操作完成后执行。
    添加操作之间的依赖关系,方便的控制执行顺序。
    设定操作执行的优先级。
    可以很方便的取消一个操作的执行。
    使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled。
    NSOperationQueue操作队列,不同于GCD中的调度队列FIFO(先进先出)原则。
    NSOperationQueue操作队列中的任务的执行顺序,受到任务的isReady状态和任务的队列优先级及依赖影响。
    NSOperationQueue有两种不同类型的队列:主队列和自定义队列。主队列在主纯种上运行,而自定义队列在后台执行。这两种队列中加入的任务都需要用NSOperation的子类来表示。
    //创建一个自定义队列
    NSOperationQueue * customQueue = [[NSOperationQueue alloc] init];
    //创建一个主队列
    NSOperationQueue * mainQueue = [NSOperationQueue mainQueue];

https://www.jianshu.com/p/89b3edfb43ce
https://www.jianshu.com/p/4b1d77054b35

  • 主队列异步任务
    因为是在主队列添加任务,所以需要等1秒后才可以执行异步任务
    dispatch_queue_t queue = dispatch_get_main_queue();

    //异步任务1
    dispatch_async(queue, ^{
        //异步任务2
        dispatch_async(queue, ^{
            sleep(2);
            NSLog(@"%@-------------1",[NSThread currentThread]);
        });
        NSLog(@"%@-------------2",[NSThread currentThread]);
        //异步任务3
        dispatch_async(queue, ^{
            NSLog(@"%@------------3",[NSThread currentThread]);
        });
    });
    
    sleep(1);
    
    //1、向主队列中添加异步任务1
    //2、等待1秒
    //3、执行异步任务1
    //  3.1、向主队列中添加异步任务2
    //  3.2、输出2
    //  3.3、向主队列中添加异步任务3
    //4、执行异步任务2
    //  4.1、等待2秒
    //  4.2、输出1
    //5、执行异步任务3
    //  5.1、输出3
  • 全局队列异步任务
    因为全局队列是异步队列,所以添加后立即执行。
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //异步任务1
    dispatch_async(queue, ^{
        //异步任务2
        dispatch_async(queue, ^{
            sleep(2);
            NSLog(@"%@-------------1",[NSThread currentThread]);
        });
        NSLog(@"%@-------------2",[NSThread currentThread]);
        //异步任务3
        dispatch_async(queue, ^{
            NSLog(@"%@-------------3",[NSThread currentThread]);
        });
    });
    sleep(1);
    
    //1、向全局队列中添加异步任务1,并开始执行
    //2、原线程等待1秒
    //3、执行异步任务1
    //  3.1、向全局队列中添加异步任务2,并开始执行
    //      3.1.1、等待2秒,2秒后输出1
    //  3.2、输出2
    //  3.3、向全局队列中添加异步任务3,并开始执行
    //      3.3.1、输出3
    //
    //      3.1.2、2秒已过,输出1

  • NSOpertaionQueue是异步队列, maxConcurrentOperationCount = 1是为串行,大于1时为并发。
    NSOperationQueue * opQueue = [[NSOperationQueue alloc] init];
    opQueue.maxConcurrentOperationCount = 1;
    
    //任务1
    [opQueue addOperationWithBlock:^{
        //任务2
        [opQueue addOperationWithBlock:^{
            sleep(1);
            NSLog(@"%@-------------1",[NSThread currentThread]);
        }];
        NSLog(@"%@-------------2",[NSThread currentThread]);
        //任务3
        [opQueue addOperationWithBlock:^{
            NSLog(@"%@-------------3",[NSThread currentThread]);
        }];
        
    }];

    //opQueue.maxConcurrentOperationCount = 1; 运行步骤
    //1、添加任务1到队列中
    //2、执行任务1
    //  2.1、添加任务2到队列中
    //  2.2、输出2
    //  2.3、添加任务3到队列中
    //  2.4、执行任务2
    //      2.4.1、等待1秒,1秒后输出1
    //      2.4.2、1秒已过,输出1
    //  2.5、执行任务3,
    //      2.5.1、输出3

    //opQueue.maxConcurrentOperationCount = 2; 运行步骤
    //1、添加任务1到队列中
    //2、执行任务1
    //  2.1、添加任务2到队列中
    //  2.2、执行任务2
    //      2.2.1、等待1秒,1秒后输出1
    //  2.3、输出2
    //  2.4、添加任务3到队列中
    //  2.5、执行任务3,
    //      2.5.1、输出3
    //      2.2.2、1秒已过,输出1
  • 不管调用多少次都只执行一次的方法
static int methoedCount = 0;
- (void)onceMethed
{
    @synchronized (self) {
        if (methoedCount == 0) {

            NSLog(@"只执行一次");
            methoedCount = 1;
        }
    }
}

- (void)onceMethed2
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只执行一次");
    });
}
  • 在一定时间内不论调用多少次,只执行最后一次。
- (void)afterDelay2{
    
    __block ViewController * vc = self;
    //全局block用来保存要执行的方法及参数
    self.clickBlock = ^ {
        [vc test];
        vc = nil;
    };
    NSLog(@"%@",self.clickBlock);
    
    //判断tiemr是否存在,存在直接return。
    if (self.timer){
        return;
    }
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //创建定时器。
        self.timer = [NSTimer timerWithTimeInterval:3 repeats:NO block:^(NSTimer * _Nonnull timer) {
            
            
            //在指定的时间结束后,调用block
            self.clickBlock();
            
            //销毁timer
            [self.timer invalidate];
            self.timer = nil;
        }];
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    });
    
}
  • 调用后开始计时,在timer时间内再次点击,重新计时。只调用最后一次。
- (void)afterDelay1{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(block2) object:nil];
    [self performSelector:@selector(block2) withObject:nil afterDelay:0.5];
}

相关文章

网友评论

      本文标题:iOS 多线程

      本文链接:https://www.haomeiwen.com/subject/hhzbqktx.html