• 【学习笔记】多线程


    网络上关于多线程的原理和用法的解释,随便一搜一大堆,但是那个宽泛过于学术性的解释,我看着太费力了。

    我就用自己比较容易理解的白话来记录一下我学到的知识吧。

    一、进程

      在移动端,一个app就是一个进程,在内存中占用一定的空间。

      在计算机里,一个程序就是一个进程,同样也占用内存空间。

      iOS同一时间点只有一个进程在使用CPU,只是系统把这个时间片分割地非常短,造成一种多个进程同时在执行的假象。

    二、线程

      一个进程的执行,必然从一个主线程开始。

      整个应用可以由单个主线程运行,但是涉及到一些耗时的任务,例如打开淘宝app,必然要加载一大堆的图片。

      这时,如果只有单线程执行,程序必须等着图片都加载完毕才能继续往下执行,期间用户的交互就不起作用,这样用户体验很不好。

      所以,这时就衍生出多线程的概念,可以开子线程给那些耗时的任务,在旁边默默地执行,而不影响应用的大局。

      主线程,一般用来处理主体的展示(例如控制器的切换)和交互事件。

      子线程,一般用来处理耗时的任务。

      当然,并不是线程越多越好,多线程的使用也是要慎重考虑。

    三、同步和异步

      我之前一直对同步和异步这个概念理解不清,常常混淆。同步是线程安全呢,还是异步线程安全呢?

      今天终于记清楚了这个概念,只要记住一句话——同步,就是同类;异步,就是异类。

      已经是同类,那肯定是处于同一个线程;异类,那就说明不是一个线程。

    四、并行和串行

      并行:并发执行

      串行:按顺序执行,一个接一个

    五、三种常用创建多线程方式

      1、NSThread:程序员手动管理线程,而多线程的情况下,线程什么时候执行完毕是未知的,如果管理不好,会造成内存泄露,所以这种方法不提倡。

      2 、NSOperationNSOperationQueue。这两个类必须是搭配使用的,将操作放入操作队列中,依次执行。

      1>使用步骤:

      * 创建NSOperation

      * 添加NSOperation到NSOperationQueue

      2>优点:

      * 更加面向对象

      * 可以控制最大并发数 maxConcurrentOperationCount,使用这个属性可以保证同一时间内最大的并发数

      * 添加任务(Operation)之间的依赖 addDependency,使用这个属性可以控制一个Operation必须在其依赖的Operation执行完毕后才调用

    //1.首先声明一个全局变量
    NSOperationQueue *_queue;
    
    //2.定义变量
    _queue = [[NSOperationQueue alloc] init];
    // 控制最大并发数:2
    _queue.maxConcurrentOperationCount = 2;
    
    //3.具体某个方法开启多线程
    NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载图片-%@", [NSThread currentThread]);
    }];
        
    NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"滤镜处理-%@", [NSThread currentThread]);
    }];
        
    // op1依赖于op(op执行完,才能执行op1)
    [op1 addDependency:op];
    
    //操作加入队列
    [_queue addOperation:op];
    [_queue addOperation:op1];
    

      

      3、GCD(官方推荐使用,纯C语言)

      调用同步(异步)执行的方法传入要并行(串行)执行的队列参数,执行方法内的block代码。

      说白了就是同一时间有一个还是多个线程执行,就看调用的方法和传入的队列类型。

      1> 队列类型

       * 全局队列  

        * 所有添加到全局队列中的任务都是并发执行(同时执行,可能会开启多个线程)  

        * dispatch_get_global_queue  

      * 串行队列  

        * 所有添加到串行队列中的任务都是按顺序执行(开一条线程)   

        * dispatch_queue_create("myqueue", 0);  

      * 主队列  

        * 所有添加到主队列中的任务都是在主线程中执行的(跟方法名没有关系)    

        * dispatch_get_main_queue  

      2> 同步还是异步,取决于方法名(不影响主队列,影响全局队列、串行队列) 

        * 同步:dispatch_sync,在当前线程执行任务,不会开启新的线程 

        * 异步:dispatch_async,在其他线程执行任务,会开启新的线程

      3>代码demo演示:

      从组合学上说,总是共有四种情况:串行-同步、串行-异步、并行-同步、并行-异步。

      串行-同步:显然一直只有一个线程在执行(这个就是真正意义上单线程)

      串行-异步:可能会产生多个线程,但是同一时间只有一个线程在执行(异步虽然会产生多个不同线程,但是同一时间只有一个线程在执行)

      并行-同步:同一时间点有多个相同的线程在执行

      并行-异步:同一时间有多个不同的线程在执行(这是真正意义上的多线程)

      下面就只举两个例子,剩下的2种情况举一反三就是了

    //串行队列,执行同步方法。说明只有一个线程在执行
    dispatch_queue_t queue = dispatch_queue_create("myqueue", 0);
    dispatch_sync(queue, ^{ // 耗时操作
        NSLog(@"dispatch_async-%@", [NSThread currentThread]);
    });
    
    //并行队列,异步执行。说明同一时间多个线程一起执行
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^{ // 耗时操作
        NSLog(@"dispatch_async-%@", [NSThread currentThread]);
    });
    

      

      而主队列的使用,常常用来执行完子线程后,要讲数据返回主线程来进行处理。

      比如开启子线程下载某个资源,下载完毕需要回调到主线程来展示。

      可以在子线程完成的时候调用以下的方法返回主线程,同时能够将子线程得到的参数传给处理的selector方法里执行。

      [xxx performSelectorOnMainThread:@selector(xxx:) withObject:xxx waitUntilDone:YES]

      4、开启后台线程

     [self performSelectorInBackground:@selector(test) withObject:nil]
    

      

    六、总结

      多线程是很重要的点,这些只是我目前掌握的理解,可能有很多不足和理解偏差,以后慢慢改进,继续补充。 

     

  • 相关阅读:
    php IE中文乱码
    Ehab and a 2-operation task (思维题)
    9-7链表数据求和操作
    "巴卡斯杯" 中国大学生程序设计竞赛
    Codeup 问题 B: 算法7-16:弗洛伊德最短路径算法
    一只小蜜蜂...
    结构体作为函数参数(值传递,引用传递,指针传递)
    Codeforces Round # 515 (div.3) A. Vova and Train
    查找最大元素
    JSP复习(part 4)
  • 原文地址:https://www.cnblogs.com/chuichou0306/p/4095856.html
Copyright © 2020-2023  润新知