PYTHON2.day08
前情回顾
1. 进程间通信
共享内存 : 在内存中开辟空间,只能存一组数据,效率
高
Value() --> 单一数据
Array() --> 存放数组,字符串等
信号量 : Semaphore() 创建信号量
acquire() 消耗信号量
release() 增加信号量
2. 什么是线程:
线程特点
创建多线程
threading --> Thread
Thread() 创建线程对象
start() 启动线程
join() 回收线程
线程对象属性
t.name 名称
t.daemon 主线程退出后分支线程是否退出
t.is_alive() 查看状态
currentThread() 获取线程对象
自定义线程类
1. 继承Thread
2. 编写自己的__init__
3. 重写run
线程通信
1.通信方法:全局变量
2. 同步互斥方法
Event()
e.set() e.wait() e.clear() e.is_set()
Lock()
acquire() release()
4.线程的GIL问题
全局解释器锁:同一时刻只有一个线程被解释,直接导致python线程效率低下
一.测试
1.结论:在无阻塞状态下,多线程程序和单线程程序执行效率几乎差不多,甚至还不如单线程效率
但是多线程运行相同的内容却可以有明显的效率提升
2.python线程的GIL问题(全局解释器锁)
【1】什么是GIL问题
由于python 解释器设计中加入了解释器锁,
导致python解释器同一时刻只能解释一个线程,大大降低了执行效率
【2】导致后果,因为遇到阻塞时线程会让出解释器,去解释其他线程,
所以python多线程在执行多阻塞高延迟IO时可以提升程序效率,
其他情况并不能对效率有所提升
【3】*尽量使用进程完成无阻塞的并发行为
*不使用c作为解释器(java c#)
二.进程线程的区别联系
【1】区别和联系
1.两者都是多任务编程方式,都能使用多核资源
2.进程的创建删除消耗的计算机资源比线程多
3.进程的空间多,数据不相干扰,有专门通信的方法:线程使用那些局部变量通信
4.有个进程可以有多个分支线程,两者有包含关系
5.多个线程共享进程资源,在共享资源操作时往往需要同步互斥处理
6.进程线程在系统中都有自己的特有属性标志,如ID,代码段命令集等
【2】使用场景
1.任务场景:如果是相对独立的任务模块,可能使用多进程,
如果是多个分支共同形成一个整体任务可能用多线程
2.项目结构:多种编程语言实现不同任务模块,可能是多进程,或者后端分离应该各自为一个进程
3.难易程度:通信难度,数据处理的复杂度来判断进程间通信还是同步互斥
【3】要求:1.对进程线程怎么理解/说说进程线程的差异
2.进程间通信有哪些,有什么特点
3.什么是同步互斥,什么情况下使用,用什么
4.给一个情形,说说用进程还是线程,为什么
5.同一个概念,僵尸进程的处理,GIL问题,进程状态。
三.网络通信模型
1.通信模型分类
【1】循环服务器模型:
循环接收客户端请求,处理请求,同一时刻只能处理一个请求,
处理完毕再处理下一个
优点:实现简单占有资源少
缺点:无法同时处理多个客户端请求
适用情况:处理的任务可以很快完成,客户端无需长期占用服务端程序,
udp比tcp更适合循环
【2】IO并发模型:利用IO多路复用技术可以同时处理多个客户端IO请求
优点:资源消耗少,能同时高效处理多个IO行为
缺点:只能处理并发的IO事件,无法处理cpu计算
适用情况:HTTP请求,网络传输等都是IO行为,都可以充分可利用IO多路复用
【3】多进程/线程的网络并发模型:
每当一个客户端连接服务器,就创建一个新的进程/线程我该客户服务,
客户端退出时销毁该进程/线程
缺点:资源消耗较大
使用情况:客户点同时连接量较少,需要处理行为较复杂情况。
2.层多进程网络并发模型
【1】基于fork的并发模型
1.创建监听套接字
2.等待接收客户端请求
3.客户端连接创建新的进程处理客户端请求
4.原来进程继续等待其他客户端连接
5.如果客户端退出,则销毁的对应的进程
四.ftp文件服务器
1.功能:
【1】分为服务端和客户端,要求可以有多个客户端同时操作
【2】客户端可以查看文件库中有什么样的文件
【3】客户端可以从文件库中下载文件到本地
【4】客户端可以上传文件到文件库
【5】使用print客户端打印输入提示,引导操作
2.技术分析
(1)使用fork多进程并发
(2)tcp套接字传输
(3)获取文件列表os.listdir()
判断普通文件os.path.isfile()
3.结构设计(操作流程)
(1)客户端启动后打印界面
(2)客户端发起请求后服务器要判断能否处理将结果反馈给客户端
(3)若不能处理则终止请求行为,能处理子具体操作
(4)将文件的具体功能封装为类
4.具体功能分析
(1)搭建网络连接
(2)查看文件列表
(3)下载文件
(4)上传文件
(5)客户端退出
1 #服务端 2 '''ftp文件服务器 3 fork server训练 4 ''' 5 from socket import * 6 import os,sys 7 from time import sleep 8 import signal 9 import time 10 11 #全局变量 12 HOST = '0.0.0.0' 13 PORT = 8888 14 ADDR = (HOST,PORT) 15 FILE_PATH = '/home/tarena/wenjan/' 16 17 class FtpServer(object): 18 def __init__(self,connfd): 19 self.connfd = connfd 20 21 def do_list(self): 22 #获取文件列表 23 file_list = os.listdir(FILE_PATH) 24 if not file_list: 25 self.connfd.send("文件库问空".encode()) 26 return 27 else: 28 self.connfd.send(b'OK') 29 time.sleep(0.1) 30 31 files = "" 32 for file in file_list: 33 if file[0] != '.' and os.path.isfile(FILE_PATH+file): 34 files = files + file + ',' 35 36 #将拼接好的字符串传给客户端 37 self.connfd.send(files.encode()) 38 39 40 41 def do_get(self,filename): 42 try: 43 fd = open(FILE_PATH+filename,'rb') 44 except IOError: 45 self.connfd.send("文件不存在".encode()) 46 return 47 else: 48 self.connfd.send(b'OK') 49 time.sleep(0.1) 50 #发送文件内容 51 while True: 52 data = fd.read(1024) 53 if not data: 54 time.sleep(0.1) 55 self.connfd.send(b'##') 56 break 57 self.connfd.send(data) 58 59 60 def do_put(self,filename): 61 if os.path.exists(FILE_PATH + filename): 62 self.connfd.send('文件存在'.encode()) 63 return 64 try: 65 fd = open(FILE_PATH+filename,'wb') 66 except: 67 self.connfd.send('上传失败'.encode()) 68 return 69 self.connfd.send(b'OK') 70 #接收文件 71 while True: 72 data = self.connfd.recv(1024) 73 if data == b'##': 74 break 75 fd.write(data) 76 fd.close() 77 78 79 80 def do_request(connfd): 81 ftp = FtpServer(connfd) 82 while True: 83 data = connfd.recv(1024).decode() 84 if not data or data[0] =='Q': 85 connfd.close() 86 return 87 elif data[0] == 'L': 88 ftp.do_list() 89 elif data[0] =='G': 90 filename = data.split(" ")[-1] 91 ftp.do_get(filename) 92 elif data[0] == 'P': 93 filename = data.split(' ')[-1] 94 ftp.do_put(filename) 95 96 97 98 99 100 #网络搭建 101 def main(): 102 #连接网络 103 #创建套接字 104 sockfd = socket() 105 sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#循环 106 sockfd.bind(ADDR)#绑定 107 sockfd.listen(5)#监听 108 print("Listen to the port 8888 ...") 109 #处理僵尸进程 110 signal.signal(signal.SIGCHLD,signal.SIG_IGN) 111 112 while True: 113 try: 114 connfd,addr = sockfd.accept() 115 except KeyboardInterrupt: 116 sockfd.close() 117 sys,exit("服务器退出") 118 except Exception as e: 119 print("服务器异常:",e) 120 continue 121 print("连接客户顿:",addr) 122 123 #创建子进程处理客户端请求 124 pid = os.fork() 125 if pid ==0: 126 sockfd.close() 127 do_request(connfd)#处理客户端请求 128 os._exit(0) 129 #无论是父进程或者创建进程失败都是逊汗接收新的连接 130 else: 131 connfd.close() 132 133 if __name__=="__main__": 134 main()
1 #客户端 2 from socket import * 3 import sys 4 import time 5 6 #具体功能 7 class FtpClient(object): 8 def __init__(self,sockfd): 9 self.sockfd = sockfd 10 11 12 def do_list(self): 13 self.sockfd.send(b'L')#发送请求 14 #等待回复 15 data = self.sockfd.recv(128).decode() 16 if data =='OK': 17 #接收文件名称 18 data = self.sockfd.recv(4096).decode() 19 files = data.split(',') 20 for file in files: 21 print(file) 22 else: 23 #无法完成操作 24 print(data) 25 26 27 def do_quit(self): 28 self.sockfd.send(b'Q') 29 self.sockfd.close() 30 sys.exit("谢谢使用") 31 32 33 def do_get(self,filename): 34 self.sockfd.send(('G '+filename).encode()) 35 data = self.sockfd.recv(128).decode() 36 if data == 'OK': 37 fd = open(filename,'wb') 38 while True: 39 data = self.sockfd.recv(1024) 40 if data == b'##': 41 break 42 fd.write(data) 43 fd.close() 44 else: 45 print(data) 46 47 def do_put(self,filename): 48 try: 49 f = open(filename,'rb') 50 except Exception: 51 print("没有找打文件") 52 return 53 filename = filename.split('/')[-1] 54 self.sockfd.send(('P '+filename).encode()) 55 data = self.sockfd.recv(128).decode() 56 if data == 'OK': 57 while True: 58 data = f.read(1024) 59 if not data: 60 time.sleep(0.1) 61 self.sockfd.send(b'##') 62 break 63 self.sockfd.send(data) 64 f.close() 65 print("%s上传完毕"%filename) 66 else: 67 print(data) 68 69 70 71 #网络连接 72 def main(): 73 #服务器地址 74 ADDR = ('127.0.0.1',8888) 75 76 sockfd = socket() 77 try: 78 sockfd.connect(ADDR) 79 except Exception as e: 80 print("连接服务器失败:",e) 81 return 82 83 #创建文件处理类对象 84 ftp = FtpClient(sockfd)#把sockfd -->属性 85 86 87 while True: 88 print("\n-------------命令选项------------") 89 print("*** list ***") 90 print("*** get file ***") 91 print("*** put file ***") 92 print("*** quit ***") 93 print("----------------------------------") 94 95 cmd = input("输入命令>>") 96 if cmd.strip() == 'list': 97 ftp.do_list() 98 elif cmd[:3] == 'get': 99 filename = cmd.strip().split(' ')[-1] 100 ftp.do_get(filename) 101 elif cmd.strip() == 'quit': 102 ftp.do_quit() 103 elif cmd[:3] == 'put': 104 filename = cmd.split(' ')[-1] 105 ftp.do_put(filename) 106 else: 107 print("请输入正确命令") 108 109 110 111 112 113 if __name__=="__main__": 114 main()
作业:1.完成文件服务器上传功能
2.复习http协议和httpserver1.0
3.复习mysql的基本语句
4.自己完成进程线程基础程序fork Process Thread