复习
上节课复习: 1、操作系统(现代操作系统): 操作系统是位于计算机硬件于软件之间的控制程序 作用: 1、将硬件的复杂操作封装成简单的接口,给用户或者应用程序使用 2、将多个应用程序对硬件的竞争变的有序 2、进程 一个正在运行的程序,或者说是一个程序的运行过程 3、串行、并发、并行 串行:一个任务完完整运行完毕,才执行下一个 并发:多个任务看起来是同时运行的,单核就可以实现并发 并行:多个任务是真正意义上的同时运行,只有多核才能实现并行 4、多道技术 背景:想要再单核下实现并发(单核同一时刻只能执行一个任务) 并发实现的本质就:切换+保存状态 多道技术: 1、空间上的复用=》多个任务共用一个内存条,但占用内存是彼此隔离的,而且是物理层面隔离的 2、时间上的复用=》多个任务共用同一个cpu 切换: 1、遇到io切换 2、一个任务占用cpu时间过长,或者有另外一个优先级更高的任务抢走cpu 今日内容: 进程: 1、进程理论 2、开启进程的两种方式 3、进程对象相关的属性或方法 线程: 4、线程理论 5、开启线程的两种方式 6、先从对象相关的属性或方法
进程:
1、进程理论
2、开启进程的两种方式
3、进程对象相关的属性或方法
今日作业:
不用socketserver 实现并发通信
用多进程实现并发通信
from socket import * from multiprocessing import Process server=socket(AF_INET,SOCK_STREAM) server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) def talk(conn,client_addr): while True: try: msg=conn.recv(1024) if not msg:break conn.send(msg.upper()) msg = msg.decode('utf-8') print(msg) except Exception: break if __name__ == '__main__': #windows下start进程一定要写到这下面 while True: conn,client_addr=server.accept() print(conn,client_addr) p=Process(target=talk,args=(conn,client_addr)) p.start()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) while True: msg=input('>>: ').strip() if len(msg) == 0:continue phone.send(msg.encode('utf-8')) data=phone.recv(1024) print(data.decode('utf-8')) phone.close()
1、进程理论
进程是对正在运行程序的一个抽象 操作系统的其他所有内容都是围绕进程的概念展开的 操作系统的两大功能: 1、将硬件的复杂操作封装成简单的接口,给用户或者应用程序使用 2、将多个应用程序对硬件的竞争变的有序 应用程序请求---》操作系统----》cpu 真正干活的是cpu,cpu同一时刻只能执行一个任务 多道技术就是为了并发产生的:切换+保存状态 cpu+多道技术就可以实现并发 多道技术解决二代计算机的串行执行问题: 1、空间上的复用=》多个任务共用一个内存条,但占用内存是彼此隔离的,而且是物理层面隔离的 2、时间上的复用=》多个任务共用同一个cpu 切换: 1、遇到io切换 2、一个任务占用cpu时间过长,或者有另外一个优先级更高的任务抢走cpu 操作系统控制执行多道技术:应用程序向操作系统发起请求,操作系统控制cpu执行程序,根据空间和时间的复用来分配cpu。实现并发 time.sleep(sleep) 模拟i/o --》 操作系统 --》 cpu切换执行别的程序
2、开启进程的两种方式
# # 方式一:process from multiprocessing import Process import time def task(x): print('%s is running' %x) time.sleep(3) print('%s is done' %x) if __name__ == '__main__': p=Process(target=task,args=('子进程',)) # 如果args=(),括号内只有一个参数,一定记住加逗号 调用类产生对象 p.start() # 对象绑定方法 只是向操作系统发送一个开启子进程的信号 开子进程信号放在main后 防止win系统重复导入 print('主') ##方式二:自定义类继承process方式 from multiprocessing import Process import time class Myprocess(Process): def __init__(self,x): super().__init__() self.name=x def run(self): print('%s is running' %self.name) time.sleep(3) print('%s is done' %self.name) if __name__ == '__main__': p=Myprocess('子进程1') p.start() #p.run() print('主') 子进程开启原理:向操作系统发送一个开启子进程的信号,父进程空间,数据复制一份到子进程空间 ps: windows系统中 复制父数据的方法:子进程将父文件当做模块导入子进程空间 导入的成果放入子名称空间 会重复导入,所以加main 只在当做执行文件时才会执行下面的代码 linux系统中 没有这种问题但是为了兼容性,统一标准也这么做 父进程执行完毕但不会结束,要等子进程全都结束才会统一回收pid,等资源 然后才会结束 僵尸进程是子进程运行完毕的一种状态,内存,硬盘等资源已经回收了 但是pid等 还没有回收 留给父进程查看 本身无害 父进程死掉之后,子进程会被系统的init最终父进程统一回收,时间可能会慢点 但是也无害 pid,内存等资源也会回收 称为孤儿进程 父进程不死的僵尸进程才是有害的,占用pid,内存 造成其他的程序起不来,因为资源已经占用完了 解决方法是:杀死父进程,让子进程自动进入init进程,统一管理,回收pid 内存 等资源 进程的内存空间是彼此隔离的,数据互不影响
3、进程对象相关的属性或方法
让父进程在原地等待,等到子进程运行完毕后,才执行下一行代码 p.start() p.join() 开启多个子进程 from multiprocessing import Process import time def task(name,n): print('%s is running ' %name) time.sleep(n) print('%s is done ' % name) if __name__ == '__main__': p_l=[] start=time.time() for i in range(1,4): p=Process(target=task,args=('子进程%s' %i,i)) p_l.append(p) p.start() for p in p_l: p.join() stop=time.time() print('主',(stop-start)) 父进程内查看子pid的方式 p.start() print(p.pid) 子进程内查看自己的pid os.getpid() 当前进程内查看父进程pid os.getppid() 父进程中查看看子进程名: p1.start() print(p.name) 子进程中查看自己的进程名 from multiprocessing import Process,current_process current_process().name 父进程中查看子进程是否存活 p1.start() print(p.is_alive()) #True p.join() print(p.is_alive()) #False 父进程中发请求---os干掉子进程 p.terminate() time.sleep(1) print(p.is_alive())