操作系统简介(转自林海峰老师博客介绍)
#一 操作系统的作用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,并且将多个进程对硬件的竞争变得有序
#二 多道技术:
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
才能保证下次切换回来时,能基于上次切走的位置继续运行
进程与程序的区别:
程序仅仅是一堆代码而已,而进程指的是程序的运行过程。
需要强调的是,同一个程序执行两次,那也是两个进程。
进程的创建都是操作系统完成的。
开启进程的两种方式:
第一种方法:
1 from multiprocessing import Process #引用这个函数 2 import time 3 def work(name): 4 print('task <%s> is runing' %name) 5 time.sleep(2) 6 print('task <%s> is done' % name) 7 8 if __name__ == '__main__': 9 # Process(target=work,kwargs={'name':'egon'}) #target后边跟的是你的函数名,传值的方式有两种:一种是args(单个参数),一种是kwargs(多个参数) 10 p1=Process(target=work,args=('egon',)) 11 p2=Process(target=work,args=('alex',)) 12 p1.start() 13 p2.start() 14 print('主')
15 #主
#task <egon> is runing
#task <alex> is runing
#task <egon> is done
#task <alex> is done
打印的结果如15所示:
为什么会先打印"主"这个字段????
是因为主程序在执行的过程中,会告诉操作系统开一个进程,但是开完进程以后,操作系统不会在这等着(相当于只是发了一个开启进程的信号),然后会继续向后边执行。
等到所有的子进程执行完后,主进程才会执行完成。(如果在执行过程中,主进程挂掉,子进程就会成为僵尸进程)
开启进程的方式二:
from multiprocessing import Process import time class MyProcess(Process): #自己定义了一个类继承一下进程的类 def __init__(self,name): super().__init__() #先重用父类的功能,然后再去定义自己的,要不然会出错。 self.name=name def run(self): print('task <%s> is runing' % self.name) time.sleep(2) print('task <%s> is done' % self.name) if __name__ == '__main__': p=MyProcess('egon') p.start() print('主')
UDP并发的套接字通信:
1 from multiprocessing import Process 2 from socket import * 3 s=socket(AF_INET,SOCK_STREAM) 4 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 5 s.bind(('127.0.0.1',8080)) 6 s.listen(5) 7 def talK(conn,addr): 8 while True: #通信循环 9 try: 10 data=conn.recv(1024) 11 if not data:break 12 conn.send(data.upper()) 13 except Exception: 14 break 15 conn.close() 16 17 if __name__ == '__main__': 18 while True: 19 conn,addr=s.accept() #链接循环 20 p=Process(target=talK,args=(conn,addr)) 21 p.start() 22 23 s.close()
#将获取地址,和链接循环放在程序主体,通信循环定义成一个模块,这样可以实现并发。
#客户端 from socket import * c=socket(AF_INET,SOCK_STREAM) c.connect(('127.0.0.1',8080)) while True: #通信循环 msg=input('>>: ').strip() if not msg:continue c.send(msg.encode('utf-8')) data=c.recv(1024) print(data.decode('utf-8')) c.close()
客户端只是个程序,当他启动了就是一个进程。
启动多个,就是多个进程。
join方法(主进程等待子进程结果):
主程序的运行过程中需要子进程的执行结果,但正常的是不等的,这时候我们需要用到join方法。
from multiprocessing import Process import time def work(name): print('task <%s> is runing' %name) time.sleep(3) print('task <%s> is done' % name) if __name__ == '__main__': p1=Process(target=work,args=('egon',)) p2=Process(target=work,args=('alex',)) p3=Process(target=work,args=('yuanhao',)) # p1.start() # p2.start() # p3.start() # # p1.join() #主进程等,等待p1运行结束 # p2.join() #主进程等,等待p2运行结束 # p3.join() #主进程等,等待p3运行结束 p_l = [p1, p2, p3] for p in p_l: p.start() for p in p_l: p.join() print('主')
这里边所有的进程都加入了join方法,但是其实是主进程把所有的进程都打开了,所有的子进程都在并发,其实主进程等待的是运行时间最长的子进程,运行时间最长的子进程结束,主进程等待结束。
#注意的一点:不能将这个开进程和join方法放到一个循环里边,这样的话,相当于是串行运行程序。等待时间是所有时间的总和。
错误的用法:
p_l = [p1, p2, p3]
for p in p_l:
p.start()
# p.join()
# p1.start()
# p1.join()
# p2.start()
# p2.join()
# p3.start()
# p3.join()
Process对象的其他方法或属性:
p=Process(target=work,args=("egon",),name="123") p1.start() #p1.terminnate() zijinchengzaikai zijincheng #热别注意,容易产生僵尸进程 #p1.is_alive() 判断这个进程是否是活着的 #p1.name() 打印p1的进程名 #p1.pid() #print("zhu",os.getpid()) #打印进程pid #print("zhu",os.getppid()) #打印父进程pid
守护进程:
主进程创建守护进程,
其一:守护进程会在主进程代码执行结束后就终止
其二:守护进程无法在开启子进程,否则抛出异常。
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。
主进程结束后,子进程也完蛋了。
应用场景:监控(比如说子进程监控主进程的状态,主进程一旦挂掉,子进程也要随之挂掉)
from multiprocessing import Process import time def work(name): print('task <%s> is runing' %name) time.sleep(2) print('task <%s> is done' % name) if __name__ == '__main__': p1=Process(target=work,args=('egon',)) p1.daemon = True p1.start() print('主')
小例子:
1 #主进程代码运行完毕,守护进程就会结束 2 from multiprocessing import Process 3 import time 4 def foo(): 5 print(123) 6 time.sleep(1) 7 print("end123") 8 9 def bar(): 10 print(456) 11 time.sleep(3) 12 print("end456") 13 if __name__ == '__main__': 14 15 p1=Process(target=foo) 16 p2=Process(target=bar) 17 18 p1.daemon=True 19 p1.start() 20 p2.start() 21 print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止