一 进程相关介绍
1.1 进程的概念(process)
- 进程就是正在运行的程序,它是操作系统中,资源分配的最小单位
- 资源分配:分配的是cpu和内存等物理资源
- 进程号是程的唯标识
- 同—个程序执行两次之后是两个进程
- 进程和进程之间的关系:数据彼此隔离,通过 socket通信
1.2 并行和并发
并发:一个cpu同一时间不停执行多个程序
并行:多个cpu同一时间不停执行多个程序
1.3 进程的调度方法
- 先来先服努fcfs( first come first server):先来的先执行
- 短作业优先算法:分配的cpu多,先把短的算完
- 时间片轮转算法:每一个任务就枘行一个时间片的时间.然后驯执行其他的
- 多级反馈队列算法
越是时间长的,cpu分配的资源越短,优先级靠后
越是时间短的,cpu分配的资源越多
1.4 进程三状态图
(1)就绪(Read)状态:只剩下CPU需要执行外,其他所有資源都已分配完毕称为就绪状态。
(2)执行(Running)状态:CPU开始执行该进程时称为执行状态。
(3)阻塞(Blocked)状态:由于等待某个事件发生而无法行时,便是阻塞状态,cpu执行其他进程.例如,等待I/O完成 input、申请缓中区不能满足等等。
1.5 同步 异步 /阻塞 非阻塞
场景在多任务当中
同步:必须等我这件事干完了,你在干,只有一条主线,就是同步
异步:没等我这件事情干完,你就在干了,有两条主线,就是异步
阻塞:比如代码有了 input,就是阻塞,必须要输入一个字符串,否则代码不往下执行
非阻塞:没有任何等待,正常代码往下执行
- 同步阻塞:效率低,cpu利用不充分
- 异步阻塞:比如 socketserver,可以同时连接多个,但是彼此都有recv
- 同步非阻塞没有类似 input的代码,从上到下执行默认的正常情况代码
- 异步非阻塞:效率是最高的,cpu过度充分,过度发热
二 python进程的相关操作
2.1 打印一个进程号
import os from multiprocessing import Process #获取子进程的ID(当前进程) res = os.getpid() print ("子进程是:",res) #获取父进程id res = os.getppid() print ("父进程是:",res)
执行
[root@node10 python]# python3 test.py 子进程是: 3452 父进程是: 3294
2.2 进程的基本语法
import os from multiprocessing import Process #获取子进程的ID(当前进程) res = os.getpid() print ("子进程是:",res) #获取父进程id res = os.getppid() print ("父进程是:",res) def func(): print("1子进程id>>>:%s,父进程id>>>:%s" % (os.getpid(),os.getppid()) ) if __name__ == "__main__": print("2子进程id>>>:%s,父进程id>>>:%s" % (os.getpid(),os.getppid()) ) # 创建子进程 target 是指定要完成的任务,后面接的是函数变量 p = Process(target=func) # 调用子进程 p.start() func()
执行
[root@node10 python]# python3 test.py 子进程是: 3468 父进程是: 3294 2子进程id>>>:3468,父进程id>>>:3294 1子进程id>>>:3468,父进程id>>>:3294 1子进程id>>>:3469,父进程id>>>:3468
2.3 带有参数的函数
import os from multiprocessing import Process def func(): for i in range(1,6): print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": print ("2子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) p = Process(target=func) #调用子进程 p.start()
执行
[root@node10 python]# python3 test.py 2子进程id:3488,父进程id:3294 1子进程id:3489,父进程id:3488 1子进程id:3489,父进程id:3488 1子进程id:3489,父进程id:3488 1子进程id:3489,父进程id:3488 1子进程id:3489,父进程id:3488
2先于1执行
import os from multiprocessing import Process def func(): for i in range(1,6): print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": print ("2子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) p = Process(target=func) #调用子进程 p.start() n = 5 for i in range(1,n+1): print ("*"*i)
执行
[root@node10 python]# python3 test.py 2子进程id:3494,父进程id:3294 * ** *** **** ***** 1子进程id:3495,父进程id:3494 1子进程id:3495,父进程id:3494 1子进程id:3495,父进程id:3494 1子进程id:3495,父进程id:3494 1子进程id:3495,父进程id:3494
带参数
import os import time from multiprocessing import Process def func(n): for i in range(1,n+1): print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": print ("2子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) n = 5 p = Process(target=func,args=(n,)) #调用子进程 p.start() for i in range(1,n+1): print ("*"*i)
执行
[root@node10 python]# python3 test.py 2子进程id:3508,父进程id:3294 * ** *** **** ***** 1子进程id:3509,父进程id:3508 1子进程id:3509,父进程id:3508 1子进程id:3509,父进程id:3508 1子进程id:3509,父进程id:3508 1子进程id:3509,父进程id:3508
加延迟,即阻塞
import os import time from multiprocessing import Process def func(n): for i in range(1,n+1): time.sleep(0.1) print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": print ("2子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) n = 5 p = Process(target=func,args=(n,)) #调用子进程 p.start() for i in range(1,n+1): time.sleep(0.1) print ("*"*i)
执行
[root@node10 python]# python3 test.py 2子进程id:3515,父进程id:3294 * 1子进程id:3516,父进程id:3515 ** 1子进程id:3516,父进程id:3515 *** 1子进程id:3516,父进程id:3515 **** 1子进程id:3516,父进程id:3515 ***** 1子进程id:3516,父进程id:3515
修改阻塞时间
import os import time from multiprocessing import Process def func(n): for i in range(1,n+1): time.sleep(0.3) print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": print ("2子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid()))
# 创建子进程,返回进程对象,如果有参数用args关键字参数进行指定
# 对应的值是元组,参数赛到元组当中,按照传递次序排列
n = 5 p = Process(target=func,args=(n,)) #调用子进程 p.start() for i in range(1,n+1): time.sleep(0.1) print ("*"*i)
执行
2子进程id:3504,父进程id:3294 * ** *** 1子进程id:3505,父进程id:3504 **** ***** 1子进程id:3505,父进程id:3504 1子进程id:3505,父进程id:3504 1子进程id:3505,父进程id:3504 1子进程id:3505,父进程id:3504
2.4 进程之间数据彼此隔离
import os import time from multiprocessing import Process count = 99 def func(): global count count += 1 print ("子进程id:%s"%(os.getpid())) print (count) if __name__ == "__main__": p = Process(target=func) p.start() print ("主进程,count=",count)
执行
[root@node10 python]# python3 test.py 主进程,count= 99 子进程id:3527 100
主进程和子进程之间是隔离的,相当于是直接复制一份,不是直接延续主进程
import os import time from multiprocessing import Process count = 99 def func(): global count count += 1 print ("子进程id:%s"%(os.getpid())) print (count) if __name__ == "__main__": p = Process(target=func) p.start() time.sleep(1) print ("主进程,count=",count)
执行
[root@node10 python]# python3 test.py 子进程id:3533 100 主进程,count= 99
2.5 多进程之间的并发
在程序并发时,因为cpu的调度策略问题,不一定谁先执行,谁后执行,任务的执行,是资源抢占的过程
import os import time from multiprocessing import Process def func(): print ("1子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid())) if __name__ == "__main__": for i in range(10): Process(target=func).start()
执行
[root@node10 python]# python3 test.py 1子进程id:3538,父进程id:3537 1子进程id:3539,父进程id:3537 1子进程id:3540,父进程id:3537 1子进程id:3541,父进程id:3537 1子进程id:3542,父进程id:3537 1子进程id:3543,父进程id:3537 1子进程id:3544,父进程id:3537 1子进程id:3545,父进程id:3537 1子进程id:3546,父进程id:3537 1子进程id:3547,父进程id:3537
把i作为参数
import os import time from multiprocessing import Process def func(i): print("i=%s,1子进程id>>>:%s,父进程id>>>:%s" % (i,os.getpid(),os.getppid()) ) if __name__ == "__main__": for i in range(10): Process(target=func,args=(i,)).start()
执行
[root@node10 python]# python3 test.py i=0,1子进程id>>>:3577,父进程id>>>:3576 i=1,1子进程id>>>:3578,父进程id>>>:3576 i=2,1子进程id>>>:3579,父进程id>>>:3576 i=3,1子进程id>>>:3580,父进程id>>>:3576 i=4,1子进程id>>>:3581,父进程id>>>:3576 i=5,1子进程id>>>:3582,父进程id>>>:3576 i=6,1子进程id>>>:3583,父进程id>>>:3576 i=7,1子进程id>>>:3584,父进程id>>>:3576 i=8,1子进程id>>>:3585,父进程id>>>:3576 i=9,1子进程id>>>:3 586,父进程id>>>:3576
2.6 子进程和父进程之间的关系
- 通常情况下,父进程(主进程)速度执行稍块,但是不绝对,在父进程执行所有代码完毕之后,会默认等待所有子进程执行完毕,然后在彻底程序,为了方便进程的管理
- 如果不等待,子进程会变成僵尸程序,在后台不停的占用内存和cpu,因为进程太多,一时找不到,并不容易.
import os import time from multiprocessing import Process def func(args): print("i=%s,1子进程id>>>:%s,父进程id>>>:%s" % (i,os.getpid(),os.getppid()) ) print("end,args= ",args) if __name__ == "__main__": for i in range(10): Process(target=func,args=(i,)).start() print("主进程执行结束")
执行
[root@node10 python]# python3 test.py i=0,1子进程id>>>:3591,父进程id>>>:3590 end,args= 0 i=1,1子进程id>>>:3592,父进程id>>>:3590 end,args= 1 i=2,1子进程id>>>:3593,父进程id>>>:3590 end,args= 2 i=3,1子进程id>>>:3594,父进程id>>>:3590 end,args= 3 i=4,1子进程id>>>:3595,父进程id>>>:3590 end,args= 4 i=5,1子进程id>>>:3596,父进程id>>>:3590 end,args= 5 i=6,1子进程id>>>:3597,父进程id>>>:3590 end,args= 6 i=7,1子进程id>>>:3598,父进程id>>>:3590 end,args= 7 主进程执行结束 i=8,1子进程id>>>:3599,父进程id>>>:3590 end,args= 8 i=9,1子进程id>
添加延迟阻塞
import os import time from multiprocessing import Process def func(args): print("i=%s,1子进程id>>>:%s,父进程id>>>:%s" % (i,os.getpid(),os.getppid()) ) time.sleep(0.3) print("end,args= ",args) if __name__ == "__main__": for i in range(10): Process(target=func,args=(i,)).start() print("主进程执行结束")
执行
[root@node10 python]# python3 test.py i=0,1子进程id>>>:3616,父进程id>>>:3615 i=1,1子进程id>>>:3617,父进程id>>>:3615 i=2,1子进程id>>>:3618,父进程id>>>:3615 i=3,1子进程id>>>:3619,父进程id>>>:3615 i=4,1子进程id>>>:3620,父进程id>>>:3615 i=5,1子进程id>>>:3621,父进程id>>>:3615 i=6,1子进程id>>>:3622,父进程id>>>:3615 i=7,1子进程id>>>:3623,父进程id>>>:3615 主进程执行结束 i=8,1子进程id>>>:3624,父进程id>>>:3615 i=9,1子进程id>>>:3625,父进程id>>>:3615 end,args= 6 end,args= 0 end,args= 3 end,args= 4 end,args= 7 end,args= 1 end,args= 2 end,args= 5 end,args= 8 end,args= 9
三 join的基本使用
3.1 基本应用
等待有子进程执行完毕之后,主进程在向下执行;
import os import time from multiprocessing import Process def func(): print("this is first thing") if __name__ == "__main__": p = Process(target=func) p.start() print("This is second thing")
执行
[root@node10 python]# python3 test.py This is second thing this is first thing
first要先执行,使用阻塞延迟
import os import time from multiprocessing import Process def func(): print("this is first thing") if __name__ == "__main__": p = Process(target=func) p.start() time.sleep(0.2) print("This is second thing")
执行
[root@node10 python]# python3 test.py this is first thing This is second thing
使用join
import os import time from multiprocessing import Process def func(): print("this is first thing") if __name__ == "__main__": p = Process(target=func) p.start() p.join() #自动加锁 print("This is second thing")
执行
[root@node10 python]# python3 test.py this is first thing This is second thing
3.2 __name__相关认知
打印__name__和__name__类型
print (__name__) print (type(__name__))
执行
[root@node10 python]# python3 ceshi.py __main__ <class 'str'>
3.3 调用自定义的模块
[root@node10 python]# vim mymoudle.py
print ("123 defined by myself") a = 111222333
调用
import mymoudle print (mymoudle.a)
执行
[root@node10 python]# python3 ceshi.py 123 defined by myself 111222333
或者
from mymoudle import a print (a)
执行
123 defined by myself
111222333
__name__:如果作为一个主文件执行,得到的时__main__,如果作为一个分模块导入,那么返回的时模块名称;是主进程,返回__main__ 不是主进程,返回模块名;
[root@node10 python]# vi mymoudle.py
print (__name__)
执行
[root@node10 python]# python3 mymoudle.py __main__
当被调用时
import mymoudle
再次执行
[root@node10 python]# python3 ceshi.py mymoudle
由于教程使用的是windows,它所执行的是引用的模式,所以必须使用(if __name__ == "__main__)判断主进程,我这里使用的时centos系统,底层的实现方式是forks实现的,可以不添加,直接可以使用,来源:老男孩教育https://www.oldboyedu.com/
import os import time from multiprocessing import Process def func(): print("this is first thing") #if __name__ == "__main__": p = Process(target=func) p.start() p.join() print("This is second thing")
执行
[root@node10 python]# python3 test.py this is first thing This is second thing
这样也不会报错,后面将直接使用linux的使用方式,如果有朋友使用windows系统做实验,请加上这个判断
3.4 多个子进程通过join加阻塞,可以和主进程进行同步控制
等子进程全部执行完毕之后,主进程在走
import os import time from multiprocessing import Process def func(index): print("第%s封邮件已经发送..."%(index)) for i in range(10): p = Process(target = func,args = (i,)) p.start() print ("发出第十封邮件...")
执行
[root@node10 python]# python3 test.py 第0封邮件已经发送... 第1封邮件已经发送... 第2封邮件已经发送... 第3封邮件已经发送... 第4封邮件已经发送... 第5封邮件已经发送... 第6封邮件已经发送... 第7封邮件已经发送... 发出第十封邮件... 第8封邮件已经发送... 第9封邮件已经发送...
使用列表,让每一个进程使用join
import os import time from multiprocessing import Process def func(index): print("第%s封邮件已经发送..."%(index)) lst = [] for i in range(10): p = Process(target = func,args = (i,)) p.start() lst.append(p) for i in lst: i.join() print ("发出第十封邮件...")
执行
第0封邮件已经发送...
第1封邮件已经发送...
第2封邮件已经发送...
第3封邮件已经发送...
第4封邮件已经发送...
第5封邮件已经发送...
第6封邮件已经发送...
第7封邮件已经发送...
第8封邮件已经发送...
第9封邮件已经发送...
发出第十封邮件...
使用第二种方法创建进程
3.5 用自定义类的方式创建进程
必须继承父类Process,里面必须用run命名方法;
基本使用
import os import time from multiprocessing import Process class MyProcess(Process): def run(self): pass p = MyProcess() p.start() print ("主进程:{}".format(os.getpid()))
执行
[root@node10 python]# python3 test.py 主进程:3823
定义子进程
import os import time from multiprocessing import Process class MyProcess(Process): def run(self): print("1子进程id>>>:%s,父进程id>>>:%s" % (os.getpid(),os.getppid()) ) p = MyProcess() p.start() print ("主进程:{}".format(os.getpid()))
执行
[root@node10 python]# python3 test.py 主进程:3823 1子进程id>>>:3824,父进程id>>>:3823
3.6 带参数的子进程函数
import os import time from multiprocessing import Process class MyProcess(Process): #这里需要传参,需要自己初始化,但是有需要调用父类方法 def __init__(self,arg): #调用一下父类的构造方法来进行初始化 super().__init__() #传入参数 self.arg = arg def run(self): print("1子进程id>>>:%s,父进程id>>>:%s" % (os.getpid(),os.getppid()) ) print (self.arg) lst = [] for i in range(10): p = MyProcess("参数:%s"%(i)) p.start() lst.append(p) for i in lst: i.join() print ("最后执行子进程:{}".format(os.getpid()))
执行
[root@node10 python]# python3 test.py 1子进程id>>>:3845,父进程id>>>:3844 参数:0 1子进程id>>>:3846,父进程id>>>:3844 参数:1 1子进程id>>>:3847,父进程id>>>:3844 参数:2 1子进程id>>>:3848,父进程id>>>:3844 参数:3 1子进程id>>>:3849,父进程id>>>:3844 参数:4 1子进程id>>>:3850,父进程id>>>:3844 参数:5 1子进程id>>>:3851,父进程id>>>:3844 参数:6 1子进程id>>>:3852,父进程id>>>:3844 参数:7 1子进程id>>>:3853,父进程id>>>:3844 参数:8 1子进程id>>>:3854,父进程id>>>:3844 参数:9 最后执行子进程:3844