Skr-Eric的网络编程课堂(九)-- 线程、进程线程的区别和联系

线程

 

什么是线程

线程也是一种多任务编程方法,可以利用计算机多核资源完成程序的并发执行。线程又被称为轻量级的进程。

 

线程特征

* 线程计算机多核分配的最小单位

* 一个进程可以包含多个线程

* 线程也是一个运行的过程,消耗计算机资源,多个线程共享进程的资源和空间

* 线程的创建删除消耗的资源都要远远小于进程

* 多个线程之间执行互不干扰

* 线程也有自己的特有属性,比如指令集 ID

 

threading 模块创建线程

 

threading.Thread()

功能 : 创建线程对象

参数 :name  线程名称  默认 Thread-1

       target  线程函数

       args  元组   给线程函数位置传参

       kwargs  字典  给线程函数键值传参

 

t.start()  启动线程 自动运行线程函数

t.join([timeout])  回收线程

 

线程对象属性

 

t.is_alive()  查看线程状态

t.name  线程名称

t.setName()  设置线程名称

t.getName()  获取线程名称

threading.currentThread()  获取当前线程对象

 

t.daemon 属性

默认情况主线程退出不会影响分支线程执行

如果设置为True 则分支线程随主线程退出

 

设置方法:

t.daenon = True

t.setDaemon(True)

 

判断属性值

t.isDaemon()

* 要在start前设置,不会和join同用

 

创建自己的线程类

步骤:

1.继承Thread

2.加载Thread中的__init__

3.重写run方法

 

线程通信

    

    通信方法: 多个线程共享进程的空间,所以线程间通信使用全局变量完成。

    注意事项: 线程间使用全局变量往往要同步互斥机制保证通信安全

 

线程同步互斥方法

 

线程的event

e = threading.Event()  创建事件对象

e.wait([timeout])  如果e为设置状态则不阻塞否则阻塞

e.set()  将e变为设置状态

e.clear()  清除设置

 

线程锁

lock = threading.Lock()  创建锁对象

lock.acquire()  上锁

lock.release()  解锁

* 也可以通过with上锁,上锁状态调用acquire会阻塞

 

python线程的GIL问题 (全局解释器锁)

 

python--》支持多线程--》同步互斥--》加锁--》

超级锁,给解释器加锁--》解释器同一时刻只能解释一个线程

 

后果 : 一个解释器同一时刻只能解释执行一个线程,所以导致python线程效率低下。但是当遇到IO阻塞时线程会主动让出解释器,因此python线程更加适合高延迟的IO程序并发。

 

解决方法:

* 尽量用进程完成并发

* 不适用c解释器  c#  java

* 尽量使用多种方案组合的方式进行并发操作,线程用作高延迟IO

 

效率测试

Line cpu: 9.014907121658325

Line IO: 4.548823118209839

 

thread cpu: 9.38966417312622

thread  IO: 4.6143529415130615

 

Process  cpu: 5.466824531555176

Process  IO: 2.9468178749084473

 

进程线程的区别和联系

 

1. 两者都是多任务编程方式,都能够使用计算机的多核资源

2. 进程的创建删除消耗的计算机资源比线程要多

3. 进程空间独立,数据相互不干扰,有专门的IPC,线程使用全局变量进行通信

4. 一个进程可以创建多个线程分支,两者之间存在包含关系

5. 多个线程公用进程的资源,在资源操作时往往需要同步互斥

6. 进程线程在系统中都有自己特有的属性,ID,代码段,栈区等资源

 

使用场景

* 需要创建较多并发,同时任务关联性比较强时一般用多线程

* 不同的任务模块可能更多使用进程

* 使用进程线程需要考虑数据的处理复杂度,比如进程间通   信是否方便,同步互斥是否过于复杂

 

要求 :

1. 进程线程的区别和联系

2. 进程间通信方式都知道哪些,有什么特点

3. 同步互斥意义是什么,什么情况下用

4. 给一个情形,分析下用进程还是用线程,理由

5. 一些常见概念挖掘 : 僵尸进程,  进程状态,GIL

 

司机和售票员的故事

   * 创建父子进程分别代表司机和售票员

   * 当售票员收到SIGINT信号,给司机发送SIGUSR1信号此时司机打印"老司机开车了"

     当售票员收到SIGQUIT信号,给司机发送SIGUSR2信号此时司机打印"车速有点快,系好安全带"

     当司机捕捉到SIGTSTP信号,给售票员发送SIGUSR1,售票员打印"到站了,请下车"

   * 到站后 售票员先下车,司机下车 (子进程先退出)

 

 

 

 

 

想要看更多的课程请微信关注SkrEric的编程课堂

你可能感兴趣的:(多线程)