线程

线程

    一、什么是线程

    二、怎么创建线程

    三、线程与进程的关系       ——重点

    四、线程的作用与如何使用线程   ——重点

    五、线程的特点          ——重点

    六、守护线程daemon

    七、线程 Thread 中的三把锁(Lock,Rlock,Semaphore

    八、Thread 类的常用属性

JoinableQueue 列队

    join:等待某个任务的完成;able: ......的能力; Queue:列队

    ——可以被 join 的列队

  p = JoinableQueue()

    p.put()    ——放入值

    p.get()    ——取出值

    p.task_done  ——告诉这个列队数据已经被处理完了

      task_done 的次数应该等于 put 的调用次数  

    p.join     ——等待列表中的数据被处理完毕

一、什么是线程:

  线程是操作系统最小的运算调度单位,是独立调度和分派的基本单位,被包含在进程中,是进程中的实际运作单位,一条线程指的是进程中的一个单一顺序的控制流

二、怎么创建线程:

  1、实例化Thread类,target参数用于指定子线程要执行的任务

  2、继承Thread类,覆盖run方法

三、线程与进程的关系  ——重点

  线程不能单独存在 必须存在于进程中,

  进程是一个资源单位,其包含了运行程序所需的所有资源

  线程才是真正的执行单位没有线程,进程中的资源无法被利用起来,所以一个进程至少包含一个线程,称之为主线程

  当我们启动一个程序时,操作系统就会为这个程序创建一个主线程,线程可以由程序后期开启 ,自己开启线程称之为子线程

四、进程的作用与如何使用线程    ——重点

  1、进程的作用:

    目的只有一个就是为了 提高效率,就像一个车间 如果产量更不上 就在造一条流水线当然可以再造一个新车间,那需要把原材料转运到这个新车间 ,这个过程是非常耗时的所以通常情况是创建新的流水线 而不是建造新的车间 即 一般创建新的线程,而不是创建新的进程

  2、如何使用线程  

    线程使用方法和多进程一模一样,没有任何的区别

    不过开启线程的代码可以放在任何位置,而开启进程必须放在自运行判断下面

    之所以使用方法完全相同是因为,多进程其实是为了弥补多线程的缺憾而诞生的。详见GIL锁

五、线程的特点    ——重点

  1、创建开销小(轻型实体)

  2、同一个进程中的多个线程之间的数据时共享的(共享线程资源)

  3、多个线程之间,是平等的,没有父子关系 所有线程的PID都是相同的(独立调度和可分派的基本单位)

  4、可并发执行

六、守护线程 daemon  

  一个线程可以设置为另一个线程的守护线程

  特点: 被守护线程结束后守护线程也随之结束

  守护线程会等到所有非守护线程结束后结束,前提是除了主线程之外 还有后别的非守护,如果守护线程已经完成任务立刻就结束了

七、线程 Thread 中的 锁

  1、互斥锁 Lock

    共享意味着资源的竞争线程中也存在安全问题,

    多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题

    解决方案:  加 互斥锁

  2、死锁问题

    当程序出现了不止一把锁,分别被不同的线程持有, 现有一个资源 要想使用这个资源,就必须同时具备两把锁,这时候程序就会进程无限卡死状态 ,这就称之为死锁

    Eg:

      规定:想要吃饭 必须具备盘子和筷子,但是一个人拿着盘子,等筷子;另一个人拿着筷子,等盘子。两个人都无法吃到饭。

    如何避免死锁问题;

      1)锁不要有多个,尽量只用一个

      2)如果真的发生了死锁问题,必须迫使其中一方先交出锁

  3、可重入锁(递归锁) Rlock

    Rlock 称之为递归锁或者可重入锁,Rlock不是用来解决死锁问题的

    Rlock 与 Lock唯一的区别:

      Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次 如果一个线程已经执行过acquire 其他线程将无法执行acquire

  4、信号量 Semaphore

    Semaphore(i) 锁定的代码 同时可以被 i 个线程并发访问

    Lock   锁住的程序同时只能由一个线程访问

    Semaphore(i)  锁住的程序可以同时被一个或者多个线程访问,  i 指的是可以同时被访问的个数

    用途: 仅用于控制并发访问,并不能防止并发访问时修改数据再写入时造成的问题

八、Thread 类的常用属性:

  threading 模块包含的常用方法
    import threading

      print(threading.current_thread().name)   —— 获取当前线程对象的名字
      print(threading.active_count())      —— 获取目前活跃的线程数量
      print(threading.enumerate())        —— 获取所有线程对象

  实例化 Thread

    t = Thread(name="aaa")

      t.join()                  —— 主线程等待子线程执行完毕
      print(t.name)                —— 线程名称
      print(t.is_alive())             —— 是否存活
      print(t.isdaemon())            —— 是否为守护线程

 

posted @ 2019-06-04 16:21  水天两色  阅读(156)  评论(0)    收藏  举报