效率测试
single cpu: 8.447520017623901 single IO: 5.697270393371582
Thread cpu: 8.725268125534058 Thread IO: 5.536705255508423
Process cpu: 4.151714563369751 Process IO: 3.824965000152588
结论 : 在无阻塞情况下,多线程程序运行效率和单线程几乎相近,而多进程可以有效的提高程序的运行效率
python GIL问题 (全局解释器锁)
【1】 什么是GIL :由于python解释器设计中加入了全局解释器锁,导致python解释器同时只能解释一个线程,大大降低了python的执行效率。 【2】 导致后果: 因为遇到阻塞python线程会主动让出解释器,所以python线程在高延迟,多阻塞的情况下可以提高运行效率,其他情况并不适合。 【3】 GIL问题建议 * 修改c解释器 * 尽量使用进程并发 * 不使用c作为解释器 (java c#)
【1】 区别联系 1. 两者都是多任务编程方式,都能使用计算机多核资源 2. 进程的创建和删除消耗的计算机资源比线程多 3. 进程空间独立,数据互不干扰,有专门通信方法。线程使用全局变量通信 4. 一个进程可以包含多个线程,两者存在包含关系 5. 多线程共享进程资源,对共享资源操作时往往需要同步互斥处理 6. 进程线程都是运行过程描述,有自己的属性标志
【2】 使用场景
1. 任务场景: 如果是相对独立的任务模块可能使用进程,如果是多个分支共同构成一个完整功能可能用线程 2. 项目结构:多种语言实现不同任务模块可能是多进程。 3. 语言特点:比如Java一些语言实现线程资源少效率高,Python有GIL 等 4. 难易程度: 通信难度,逻辑处理难度等考量要求 :
对进程线程怎么理解/说说进程线程差异特点进程间通信都知道哪些,有什么特点什么是同步互斥,说说你的使用情况给一个情形分析用进程还是线程去实现,怎么实现问一些概念,僵尸进程处理,GIL问题,进程状态问题就项目问实现方法,为什么通信模型分类
【1】循环网络模型:循环接收客户端请求,处理请求,同时只能处理一个客户端请求任务,处理完再进行下一个。
优点:实现简单,占用资源少 缺点:无法同时处理多个请求,效率不高 适用情况: 客户端不会长期占有服务器,任务比较小,任务量不大。udp比tcp实现更简单【2】IO并发网络模型:利用IO多路复用等IO模型技术,同时处理多个IO任务请求。
优点:资源消耗少,能同时处理多个IO 缺点:只能处理IO操作【3】多进程/线程并发:当一个客户端连接服务器,就创建一个新的进程/线程处理客户端请求,客户端退出时对应的进程/线程也随之销毁
优点: 同时满足多个客户端长期占有服务器需求,可以处理各种请求 缺点: 资源消耗较大 使用情况:客户端请求比较复杂,处理时间较长,配合较强的服务器部署技术(负载均衡,集群技术,分布式处理,缓存队列等)多进程网络并发
基于fork的并发模型
创建监听套接字循环等待客户端连接有客户端连接创建新的进程处理客户端请求原进程继续等待其他客户端连接如果客户端退出,则销毁对应进程客户端
''' ftp服务器 fork并发 ''' from socket import * import os,sys import signal import time # 全局变量 ADDR = ("0.0.0.0",9999) FILE_PATH = "/home/tarena/test/" # 服务端功能类 class FtpServer(): def __init__(self,connfd): self.connfd = connfd def do_list(self): # 获取文件列表 file_list = os.listdir(FILE_PATH) if not file_list: self.connfd.send("文件库为空".encode()) return self.connfd.send(b"OK") time.sleep(0.1) files = "" for file in file_list: if file[0] != "." and os.path.isfile(FILE_PATH+file): files += file + "#" self.connfd.send(files.encode()) def do_get(self,filename): try: fd = open(FILE_PATH + filename,"rb") except IOError: self.connfd.send("文件不存在".encode()) return else: self.connfd.send(b"OK") time.sleep(0.1) #发送文件内容 while True: data = fd.read(1024) if not data: time.sleep(0.1) self.connfd.send(b"##") break self.connfd.send(data) fd.close() def do_put(self, filename): self.connfd.send(b"OK") filename = FILE_PATH+filename #本地服务器的文件路径 fd = open(filename,"wb") while True: data = self.connfd.recv(1024) if data ==b"##": break fd.write(data) fd.close() def do_requests(connfd): ftp = FtpServer(connfd) while True: data = connfd.recv(1024).decode() if not data or data[0] == "Q": connfd.close() return elif data[0] == "L": ftp.do_list() elif data[0] == "G": filename = data.split(" ")[-1] ftp.do_get(filename) elif data[0] == "P": filename = data.split(" ")[-1] filename = filename.split("/")[-1] ftp.do_put(filename) # 网络搭建 def main(): # 创建套接字 sockfd = socket() sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) sockfd.bind(ADDR) sockfd.listen(5) signal.signal(signal.SIGCHLD,signal.SIG_IGN) print("等待连接") while True: try: connfd,addr = sockfd.accept() except KeyboardInterrupt: sockfd.close() sys.exit("服务器退出") except Exception: continue print("连接:",addr) pid = os.fork() if pid == 0: sockfd.close() do_requests(connfd) os._exit(0) else: connfd.close() if __name__ == "__main__": main()服务端
from socket import socket import sys import time # 服务器地址 ADDR = ("127.0.0.1",9999) # 客户端功能类 class FtpClient: def __init__(self,sockfd): self.sockfd = sockfd def do_list(self): self.sockfd.send(b"L") #发送请求 #等待回复 data = self.sockfd.recv(128).decode() if data == "OK": files = self.sockfd.recv(4096).decode() for file in files.split("#"): print(file) else: #无法完成操作 print(data) def do_quit(self): self.sockfd.send(b"Q") self.sockfd.close() sys.exit("谢谢使用") def do_get(self,filename): self.sockfd.send(("G " + filename).encode()) data = self.sockfd.recv(128).decode() if data == "OK": fd = open(filename,"wb") while True: data = self.sockfd.recv(1024) # print(data.decode()) if data == b"##": break fd.write(data) print("下载完成") fd.close() else: print(data) def do_put(self, filename): # filename = filename.split("/")[-1] self.sockfd.send(("P " + filename).encode()) #发送P + 整个文件路径到服务端 data = self.sockfd.recv(128).decode() if data == "OK": try: fd = open(filename,"rb") except IOError: print("文件名或路径错误") return while True: data = fd.read(1024) if not data: # time.sleep(0.1) self.sockfd.send(b"##") break self.sockfd.send(data) print("上传完成") fd.close() def main(): sockfd = socket() try: sockfd.connect(ADDR) except Exception as e: print(e) return # 创建对象调用功能函数 ftp = FtpClient(sockfd) while True: print("\n============命令选项============") print("***** 1. 列表 **********") print("***** 2. 下载文件 **********") print("***** 3. 上传文件 **********") print("***** 4. 退出 **********") print("================================") cmd = input(">>>:") if cmd.strip() == "list": ftp.do_list() elif cmd.strip() == "quit": ftp.do_quit() elif cmd.strip()[:3] == "get": filename = cmd.split(" ")[-1] ftp.do_get(filename) elif cmd.strip()[:3] == "put": filename = cmd.split(" ")[-1] ftp.do_put(filename) else: print("请输入正确指令") if __name__ == "__main__": main()