I'll try anything once

人生苦短,何妨一试

进程与线程

进程与线程的介绍

  1. 进程为一个程序执行的实例
  2. 线程是一个控制流程,可以在进程内与其他活跃的线程同时执行(并行)

其中控制流程是值顺序执行一些机器指令。进程可以包含多个线程。例如:开启一个浏览器,操作系统将创建一个进程,并开始执行这个进程的主线程。
每个线程独立执行一些列指令(一个函数)与其他的线程并行执行
线程也被称作轻量进程,因为它和进程有许多共同点,比如都是可以和其他控制流程同时运行的控制流程,说它“轻量”是因为实现一个进程比线程要繁重的多。
线程不同于进程,多个线程可以共享很多资源,特别是地址空间和数据结构等。

线程

基本三要素

  • 程序计数器
  • 寄存器

  • 大体的状态与进程类似
  • 就绪(ready)
  • 运行(running)
  • 阻塞(blocked)

与同一进程的其他线程共享的资源基本上包括数据系统资源
多线程编程一般使用共享内容空间进行线程间的通讯。因此内容空间的管理成为多线程使用的核心。
Python通过标准库的 threading 模块来管理线程
线程模块的主要组件如下:

  • 线程对象
  • Lock对象
  • Rlock对象
  • 信号对象
  • 条件对象
  • 事件对象

定义一个线程

对应参数

  • group
    • 一般为None,其为为以后一些特性预留的。
  • target
    • 该线程启动是所要执行的函数
  • name
    • 线程的名字
  • args
    • 传入给target函数的参数,要使用tuple类型
  • kwargs
    • 传入给target函数的参数, 使用字段为dict

线程的调用

  • t.start()
    • 开始执行对应的线程
  • t.join()
    • 使调用他的线程一直等待直到执行结束(线程会调用t线程,然后等待t线程完成再执行其他线程)

实现一个线程

  • 定义一个Thread类的子类
  • 覆盖__init__(self, [args])方法, 添加额外的参数
  • 最后覆盖run(self, [,args])方法实现线程需要做的事情

使用Lock实现线程的同步

因为多个线程的同时执行,必定会导致资源的竞争,从而使得线程死锁。为了解决该问题,最简单的方法就是使用锁,
当一个线程需要访问一个 共享内存时,其必须要先获得锁,才可以去使用该资源,直到其任务完成,释放锁之后,其他的线程才能去访问共享内存,完成自己的任务。总而言之,其主要是保证在同一时刻,只有一个线程能够访问共享资源。

  • 锁有两种状态: locked(资源被某一线程拿到) unlocked(资源可用)
  • 两种方法来操作锁 acquire release

遵循一下规则

  • 如果是unlocked状态,可以调用acquire将状态改为locked,并且不可多次acquire
  • 如果是locked状态, 调用acquire会一直等到其他进程release
  • 如果是unlocked状态, 调用release会出现RuntimeError
  • 如果是locked状态,调用release会释放当前资源,状态改为unlocked

虽然这样能够基本解决资源的分配问题,但是会引起不必要的开销,也会限制程序的可拓展性和可读性。若是对于多线程有优先级的分配,那么仅通过acquirerelease完全不够的。以此出现了另一个方法。

使用Rlock实现线程的同步

Rlock的全称为Reentrant Lock也就是可以重复进入的锁,其对于Lock有如下三个显著的特点

  1. 谁拿到谁释放,若是A拿到锁,则B无法释放锁,只有A可以释放
  2. 同一线程可以多次拿到锁,即可以多次acquire
  3. 同一线程acquire多少次就需要release多少次,只有最后一次的release才能将当前状态改为unlocked

所以当你需要在类外面保证线程安全,又要在类内使用同样方法的时候RLock()就很实用了

Rlock和Lock的区别

  1. 其主要的区别就是Rlock在同一线程中可以多次的进行acquire不会产生死锁(release要和acquire成对出现,出现多少次acquire,就要多少个release),但是Lock只能进行一次acquire否者会造成死锁
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

14 + 15 =