线程
一、线程
1、什么是线程:
线程也是一种多任务编程方法,可以利用计算机的多核资源完成程序的并发执行。线程被称为轻量级的进程。
2、线程特征:
* 线程是计算机多核分配的最小单位
* 一个进程可以包含多个线程
* 线程也是一个运行的过程,也要消耗计算机资源,多个线程共享共用进程的资源和空间
* 线程的创建删除消耗的资源都要远远小于进程
* 多个线程之间独立运行互不干扰
* 线程也有自己的特有属性,比如指令集,线程栈,ID,TID
3、threading 模块创建线程
1、threading.Thread()
功能: 创建线程对象
参数:name 线程名称 默认Thread-1
target 线程函数
args 元组 给线程函数位置传参
kwargs 字典 给线程函数键值传参
返回:线程对象
2、t.start() 启动线程 自动运行线程函数
3、t.join([timeout]) 回收线程
4、线程对象属性
t.is_alive() 查看线程状态
t.name 线程名称
t.setName() 设置线程名称
t.getName() 获取线程名称
threading.currentThread() 获取到当前线程对象
5、t.daemon 属性
默认情况下主线程结束退出不会影响分支线程执行,设置为True时 则分支线程随主线程退出
1、设置 daemon值方法:
t.daemon = True
t.setDaemon(True)
2、判断属性值:
t.isDaemon()
* 要在start前设置,不会和join同用
6、创建自己的线程类
步骤 :
1 继承 Thread
2 加载父类Thread中 __init__
3 重写run方法
二、线程通信
1、通信方法:多个线程共享进程空间,所以线程间通信使用全局变量完成(进程的全局变量对进程内线程均可见)
2、注意事项:线程间使用全局变量进行通信,全局变量为共享资源,往往需要同步互斥机制保证通讯安全
3、线程同步互斥方法
4、线程的event
1、创建事件对象:
e = threading.Event()
2、事件阻塞函数:如果e为设置状态则不阻塞否则阻塞
e.wait([timeout])
3、设置事件:将e变为设置状态
e.set()
4、清除事件
e.clear()
详见示例:thread_event.py
三、线程锁 Lock
lock = threading.Lock() 创建锁对象
lock.acquire() 上锁
lock.release() 解锁
with lock 上锁 (with方式上锁执行完代码块自动解锁)
* 也可以通过with上锁,上锁状态调用acquire会阻塞。
详见示例:thread_lock.py
四、python线程的GIL问题 (全局解释器锁)
1、背景:
python ---》支持多线程操作 ---》IO的同步和互斥 ---》加锁 ---》超级锁,给解释器加锁 ---》解释器同一时刻只解释一个线程,此时其他线程需要等待
2、python线程的执行效率低的原因(后果):
一个解释器,同一时刻只解释执行一个线程,此时其他线程需要等待。所以导致Python线程效率低下。但是当遇到IO阻塞时线程会主动让出解释器,因此Python线程更加适合高延迟IO程序开发。
3、python GIL问题解决方案
* 尽量使用进程完成并发
* 不使用cpython解释器,可以用 c#,java做解释器
* 尽量使用多种方案组合的方式进行并发操作,python线程可以用在高延迟多阻塞的IO情形
* 修改c解释器
五、效率测试
分别测试 多进程 多线程 单进程执行相同的IO操作和CPU操作的时间
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. 什么是线程
threading
Thread()
t.start()
t.join()
t.name t.getName t.setName t.daemon t.is_alive()
2. 自定义线程类
继承 Thread
重写 run
3. 线程通信
使用全局变量通信
线程的同步互斥
4. Python线程 GIL
影响 : 同一时刻只能解释一个线程,造成python线 程效率低
python线程 : 适用于高阻塞IO程序
***************************Day08*******************************
一、进程和线程的区别和联系
1.两者都是多任务编程的方式,都能够使用计算机的多核资源
2.进程的创建删除要比线程消耗更多的计算机资源
3. 进程空间独立,数据相互不干扰,有专门的IPC,线程使用全局变量进行通信,更加简单
4. 一个进程可以创建多个线程分支,两者之间存在包含关系
5. 多个线程公用进程的空间资源,在资源操作时往往需要同步互斥
6. 进程线程都独立执行,在系统中都有自己特有资源的属性,ID,代码段,栈区,命令集等资源
二、进程与线程的使用场景
* 需要创建较多并发,同时任务关联性比较强时一般用多线程
* 不同的任务模块可能更多使用进程
* 使用进程线程需要考虑数据的处理复杂度,比如进程间通信是否方便,同步互斥是否过于复杂
* 使用python考虑线程GIL问题
三、服务器模型
1、硬件服务器 : 主机 集群
厂商 : IBM HP 联想 浪潮
2、软件服务器 :编写的服务端应用程序,在硬件服务器上运行,一般依托硬于操作系统。给用户提供一套完整的服务
3、服务器种类:
webserver ---》 网络的后端应用服务器程序,提供数据处理和逻辑处理
httpserver ---> 接受http请求,返回http响应
邮箱服务器 ---》 处理邮件请求,进行邮件收发
文件服务器 --》提供文件的上传下载存储
4、功能实现:网络连接,逻辑处理,数据运算,数据交互,协议实现,网络数据传输。。。。
5、模型结构: C/S 客户端服务器模型
B/S 浏览器服务器模型
6、服务器目标:处理速度更快,数据安全性更强,并发量更高
1、硬件 : 更高的配置,更好的集成分布技术,更高的网络优化和网络安全技术
2、软件 : 占用更少的计算机资源,运行效率更稳定,算法更优良,安全性更好,并发性更高,更容易扩展,更合理的技术搭配
四、基础服务端模型
1、循环服务器模型:
单进程程序,循环接收客户请求,处理请求。同一时刻只能处理一个请求,处理完毕再接受下一个请求。
1、优点:实现简单,占用资源少
2、缺点:无法同时处理多客户端任务,体验差
3、适用情况:处理的任务可以短时间完成,不需要建立并发,更适合udp使用。(udp比tcp更适合循环)
2、并发服务器模型:
能够同时处理多个客户端任务请求。
1、IO 并发: IO多路复用 (协程)
优点 : 可以实现IO的并发操作,速度快,占用系统资源少
缺点 : 不能监控cpu密集型程序的情况,并能有长期阻塞
2、多进程/多线程并发: 为每个客户端创建单独的提供一个进程/线程,处理客户端请求
优点 : 每个客户端可以长期占有服务器运行程序,能够使用多核资源,可以处理IO或者cpu运算
缺点 : 消耗系统资源高
3、多进程并发模型
使用fork实现多进程并发
1、创建套接字,绑定,监听
2、等待接收客户端请求
3、创建新的进程处理客户端请求
4、原有进程继续等待接收新的客户端连接
5、如果客户端退出则关闭子进程
cookie:
在父进程中忽略子进程状态改变,子进程退出自动由系统处理
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
详见示例:fork_server.py
五、ftp 文件服务器项目
1、项目功能:
* 服务端和客户端两部分,要求启动一个服务端,可以同时处理多个客服端请求,每个客户端可能回连续发送命令
* 功能包含:1、可以查看服务器文件库中所有的普通文件(查看的文件列表)
2、从客户端可以下载文件库的文件到本地
3、可以将本地文件上传的服务端文件库
4、退出
* 客户端使用print在终端打印简单的页面命令提示,通过命令提示发起请求
2、技术分析:
1. tcp套接字更适合文件传输
2. 并发方案 ---》 fork 多进程并发
3. 每个功能都要求单独封装,整体功能写在一个类中
4. 如何搭建整体架构,完成网络通讯
5. 对文件的读写操作
6. 获取文件列表 ----》 os.listdir() ,粘包的处理
3、功能分析:
1. 获取文件列表
客户端:* 发送请求
* 得到回复判断能否获取列表
* 接收文件名称列表打印
服务端:* 接收请求
* 判断请求类型
* 判断能否满足请求,回复信息确认
* 执行请求发送文件列表
2、文件下载
客户端:* 发送请求 (文件名)
* 得到回复判断能否下载
* 下载文件
服务端:* 接收请求
* 判断请求类型
* 判断能否满足请求,回复信息确认
* 执行请求发送文件
4、cookie:
os.listdir(puth) 获取目录中文件列表 puth路径
os.path.isfile() 判断是否为普通文件
os.path.isdir() 判断是否为目录(文件夹)
要求:
1、进程线程的区别和联系
2、进程间通信方式都知道哪些,有什么特点
3、同步互斥意义是什么,什么情况下用
4、给一个情形,分析下用线程还是用线程,理由
5、一些常见概念挖掘:僵尸进程,进程状态,GIL
总结:
1. 进程线程的区别和联系
* 都是多任务编程
* 一个进程包含多个线程
* 都是动态的占有资源的,线程共享进程的资源
* 进程比线程消耗资源更多
* 进程空间独立使用特定的IPC,线程使用全局变量
2. 服务器模型
循环模型 : 同一时刻只能处理一个请求
并发模型 : IO 并发 : 多个IO任务
多进程/多线程并发 : 任何任务
3. 基于fork的多进程并发程序
每当有一个客户端连接就创建一个新的进程
4. ftp文件服务程序
****************************Day09********************************
一、多线程并发
1、threading的多线程并发
1、对比多进程并发:
*优势: 消耗资源较少
*缺点: 线程应该更注意共享资源的操作
* 在Python中应该注意GIL问题,网络延迟较高,线程并发也是一种可行的办法
2、实现步骤:
1、创建套接字,绑定,监听
2、接收客户端连接请求,创建新的线程
3、主线程继续等待接收其他客户端连接
4、分支线程执行对应的函数处理客户端具体请求
5、处理完客户端请求后分支线程自然退出,关闭客户端套接字(当客户端断开,则分支线程结束)
3、cookie:
import traceback
traceback.print_exc()
功能:更详细的打印异常信息
二、集成模块的使用
python2 SocketServer
python3 socketserver
功能:通过模块的不同类的组合完成多进程/多线程的tcp/udp的并发程序
StreamRequestHandler 处理tcp套接字请求
DatagramRequestHandler 处理udp套接字请求
TCPServer 创建tcp server
UDPServer 创建udp server
ForkingMixIn 创建多进程
ForkingTCPServer --> ForkingMixIn + TCPServer
ForkingUDPServer --> ForkingMixIn + UDPServer
ThreadingMixIn 创建多线程
ThreadingTCPServer –> ThreadingMixIn + TCPServer
ThreadingUDPServer --> ThreadingMixIn + UDPServer
三、HTTPServer V2.0
1、基于多线程并发的HTTPServer
1. 接收(客户端)浏览器http请求
2. 解析客户端请求
3. 根据解析结果返回对应内容
4. 如果没有请求内容则返回404
5. 组织数据,形成HTTP Response格式进行回发给客户端
2、升级
1. 采用多线程并发接收多个客户端请求
2. 基本的请求解析,根据请求返回相应的内容
3. 除了可以请求静态网页,也可以请求简单的数据
4. 将功能封装在一个类中
3、技术点:
1、socket tcp 套接字
2、http协议的请求响应格式
3、线程并发的创建方法(threading并发)
4、类的基本使用
4、协程基础:
1、定义:纤程,微线程。协程的本质是一个单线程程序,所以协程不能够使用计算机多核资源。
2、作用:能够高效的完成并发任务, 占用较少的资源。因此协程的并发量较高
3、原理:通过记录应用层的上下文栈区,实现在运行中进行上下文跳转,达到可以选择性的运行想要运行的部分,以提高程序的运行效率。
4、优点:消耗资源少
无需切换开销
无需同步互斥
IO并发性好
5、缺点:无法利用计算机多核
6、yiled ---》 协程实现的基本关键字
7、第三方库:
1、greenlet
greenlet.greenlet() 生成协程对象
gr.switch() 选择要执行的协程事件
2、gevent
1、将协程事件封装为函数
2、生成协程对象
gevent.spawn(func,argv)
功能:生成协程对象
参数:func 协程函数
argv 给协程函数传参
返回值:返回协程对象
3、回收协程
gevent.joinall()
功能:回收协程
参数:列表 将要回收的协程放入列表
gevent.sleep(n)
功能:设置协程阻塞,让协程跳转
参数:n 阻塞时间
4、from gevent import monkey
monkey.patch_all()
功能:修改套接字的IO阻塞行为
* 必须在socket导入之前使用(导入)
posted on 2018-10-12 16:25 破天荒的谎言、谈敷衍 阅读(213) 评论(0) 收藏 举报
浙公网安备 33010602011771号