하나 : 프로세스의 개념 (프로세스)
프로세스는 프로그램 실행 , 그것은 운영 체제이며 , 자원 할당의 최소 단위 .
자원 할당 : 할당은이다 CPU 와 메모리 및 기타 물리적 자원
프로세스 ID 프로세스의 고유 식별자
두 개의 공정을 동일 프로그램을 실행 한 후
공정 및 프로세스 간 : 서로 분리 된 데이터 , 통한 소켓 통신
II : 병렬 및 동시
동시성 : CPU가 동시에 여러 프로그램을 실행 유지
병렬 : 복수의 CPU 연속적으로 복수의 프로그램을 실행하는 동시에
세 : 는 CPU의 프로세스 스케줄링 방법
#은 선착순 FCFS는 (첫 번째 첫 번째 서버를 온) : 선착순 실행
# 짧은 운영 우선 순위 알고리즘 : 할당 CPU 와 더는 , 첫째 짧은 수를 완료
# 라운드 로빈 알고리즘 : 타임 슬라이스의 각 작업 실행 시간 . 그런 다음 상대방의 이행에 .
# 다단계 큐 스케줄링 알고리즘
더 긴 시간 , CPU 짧은 자원 할당 , 목록의 우선 순위
더 짧은 시간 , CPU 이상의 자원 할당
### 공정 3 상지도
(1) 대기 (대기) 상태
만 CPU가 외부에서 수행해야 할 , 할당 된 다른 모든 자원은 준비 상태라고합니다.
(2) 실행 (실행) 상태
CPU는 프로세스의 구현의 실행 상태라고하기 시작했다.
(3) 블록 (차단) 상태
대기가 수행 될 수 없기 때문에 이벤트가 발생하면 , 이 차단되어 CPU가 다른 프로세스를 실행할 . 예를 들어, 대기 I / O를 완료 의 INPUT , 애플리케이션 버퍼 등등 충족하고 없다.
이 세 가지 학습 콘텐츠에서 함께 아래 도핑
(1) 포착 프로세스 ID
자식 프로세스의 ID를 가져옵니다) (os.getpid 사용
) (os.getppid 사용하여 부모 프로세스 ID를 얻을 수
# 예 :
오기 OS 시간 #의 획득 서브 공정 [현재 프로세스] 이드 RES1 = os.getpid () 인쇄 (RES1)의 #은 부모 프로세스의 ID를 취득 RES2 = os.getppid () 인쇄 (RES2) # 리눅스 프로세스 사용량 하단 포크는 프로세스를 만들 수 있지만, 내부의 창에서 포크를 지원하지 않습니다.
# 에디터에서 실행중인 경우 부모 프로세스 ID는 부모 프로세스 ID는 숫자, 두 아들 프로세스 ID 번호를 실행하는이 프로그램의 과정을 실행하는 프로세스 편집기이기 때문에, 자식 프로세스 번호를 변경하게되지 않는다는 것을 발견, 프로그램 다시 실행 다시 시작 자식 프로세스를 시작합니다.
( 2 기본적인 사용) 과정
예 :
가져 오기 운영 체제 에서 멀티 프로세싱 가져 오기 프로세스 DEF FUNC () : 인쇄 ( " 1. 자식 프로세스 ID >>> % S, % S >>> 위에서 ID를 언급 부모 프로세스 " % (os.getpid (), os.getppid ())) IF __name__ == " __main__ " : 인쇄 ( " 2. 자식 프로세스 ID >>> % S % S >>> 부모 프로세스 상술 ID " % , os.getppid ()) (os.getpid ()) #가 자식 프로세스를 생성 처리 대상이 완료되는 작업을 지정 .target 되돌아가, 그 뒷면의 함수 (= 목표는 P = 프로세스 FUNC) # 자식 프로세스 호출 p.start는 ()
그 결과, 외부 함수의 상위 프로세스 ID 함수 내의 부모 및 자식 프로세스 ID 번호가 동일하므로, 그대로이지만, 각 런의 수를 변경하는 프로세스이며, 각각의 함수 내의 자식 프로세스의 개수는 변경 될 .
( 3 ) 매개 변수 기능을
동시 프로세스의은에 의존하는 CPU의 CPU 첫째 임원 누가 나중에 임원 , 에 의존하지 수 의 CPU 스케줄링 정책 에는 인수 기능 #
# 예 :
로부터 다중 처리 오기 프로세스 오기 OS DEF : FUNC ()를 위한 I 의 레인지 (1, 6 ) 인쇄 ( " 2. 자식 프로세스 ID >>> % S % S >>> 부모 프로세스는 상기 ID 한 ' % (os.getpid를 ( ) os.getppid ())) IF __name__ == " __main__ " : 인쇄 ( " 1 자식 프로세스 ID >>> % S, S % >>> 부모 프로세스 ID 위에서 언급 한 ' % (os.getpid (), OS. getppid ())) #가 자식 프로세스를 생성 = p 형 프로세스 = (대상 FUNC) # 자식 프로세스 콜 ) (p.start을 N = 5 에 대한 I 의 범위 (1, N + 1 ) 인쇄 ( " * " * I)
자식 프로세스가 스택 공간이 필요한 시간 프레임을 열 필요를 생성하기 때문에 첫 번째 인쇄 후 #은 함수 FUNC 내에서 인쇄 부수 별
스크린 샷 결과 :
함수 매개 변수는 #이있다
from multiprocessing import Process import os,time def func(n): for i in range(1,n+1): time.sleep(0.5) print("2.子进程id>>>%s,父进程id>>>%s" % (os.getpid(), os.getppid())) if __name__ == "__main__": print("1.子进程id>>>%s,父进程id>>>%s" % (os.getpid(), os.getppid())) n = 5 # 创建子进程 返回进程对象 如果有参数用args 关键字参数执行 # 对应的值是元组,参数塞到元组中,按照次序排列 p = Process(target=func,args=(n,)) p.start() for i in range(1,n+1): time.sleep(0.3) print("*" * i)
# 这时候会造成,星星和func里面打印子进程和父进程的语句相互交错
# 因为子进程开辟栈帧空间的时间极短,所有再哪个不在睡眠时间内先运行哪个进程
效果截图:
(4)进程之间的数据彼此是隔离的
#例:
from multiprocessing import Process count = 99 def func(): global count count +=1 print("我是子进程,count=",count) if __name__ == "__main__": p = Process(target=func) p.start() print("我是主进程,count=",count)
结果输出为:
我是主进程,count= 99
我是子进程,count= 100
(5)多个进程的并发
#例:
# 在程序并发时, 因为cpu的调度策略问题,不一定谁先执行,谁后执行 from multiprocessing import Process import os def func(args): print("args=%s,子进程id号>>>%s, 父进程id号>>>%s" % (args, os.getpid(), os.getppid())) if __name__ == "__main__": for i in range(10): Process(target=func, args=(i,)).start()
运行得到结果如下图:
可以看出父进程id号是不变的,子进程id号是变化的,而且子进程开启不是按顺序的是并发的。
(6)子进程和父进程之间的关系
通常情况下,父进程会比子进程速度稍快,但是不绝对
在父进程执行所有代码完毕之后,会默认等待所有子进程执行完毕
然后在彻底的终止程序,为了方便进程的管理
如果不等待,子进程会变成僵尸进程,在后台不停地占用内存和cpu资源
但是本身由于进程太多,并不容易发现
#例:
from multiprocessing import Process import os,time def func(args): print("args=%s,子进程id号>>>%s,父进程id号>>>%s" % (args, os.getpid(), os.getppid())) time.sleep(1) print("args= %s, end" % (args)) if __name__ == "__main__": for i in range(10): Process(target=func,args=(i,)).start() """ Process(target=func,args=(i,)).start() Process(target=func,args=(i,)).start() Process(target=func,args=(i,)).start() Process(target=func,args=(i,)).start() Process(target=func,args=(i,)).start() Process(target=func,args=(i,)).start() .... """ print("*******父进程*******")
运行后的结果为:
可以看出父进程号是不变的,子进程是并发的,父进程的执行语句是最快结束的,因为开启子进程需要时间,而主进程的输出没有阻塞所以最快,从print("args= %s, end" % (args))可以知道,子进程是并发的,因为sleep(1)后,如果是顺序执行的话,输出结果不是这样。
四:同步 异步 / 阻塞 非阻塞
场景在多任务当中
同步:必须等我这件事干完了,你在干,只有一条主线,就是同步
异步:没等我这件事情干完,你就在干了,有两条主线,就是异步
阻塞:比如代码有了input,就是阻塞,必须要输入一个字符串,否则代码不往下执行
非阻塞:没有任何等待,正常代码往下执行.
# 同步阻塞 :效率低,cpu利用不充分
# 异步阻塞 :比如socketserver,可以同时连接多个,但是彼此都有recv
# 同步非阻塞:没有类似input的代码,从上到下执行.默认的正常情况代码
# 异步非阻塞:效率是最高的,cpu过度充分,过度发热
(1)join阻塞基本用法
#例:
from multiprocessing import Process def func(): print("我发送第一封邮件....") if __name__ == "__main__": p = Process(target=func) p.start() # 等待p对象的这个子进程执行完毕之后,在向下执行代码 # join实际上是加了阻塞 p.join() #如果没有join,往往主进程先运行,因为子进程需要开辟栈帧空间相当于加了阻塞 print("发送第十封邮件")
输出结果为:
我发送第一封邮件....
发送第十封邮件
#程序在发送第十封邮件前加了阻塞,是的会先运行子进程结束在运行join之后的语句
(2) 多个子进程通过join 加阻塞,进行同步的控制
例:
from multiprocessing import Process import time def func(index): time.sleep(0.3) print("第%s封邮件已经发送..." % (index)) if __name__ == "__main__": lst = [] for i in range(1,10): p = Process(target=func,args=(i,)) p.start() lst.append(p) # 把列表里面的每一个进程对象去执行join() # 必须等我子进程执行完毕之后了,再向下执行,控制父子进程的同步性 for i in lst: i.join() # 等前9个邮件发送之后了,再发第十个 print("发送第十封邮件")
所以输出结果为:
第3封邮件已经发送...
第2封邮件已经发送...
第1封邮件已经发送...
第5封邮件已经发送...
第9封邮件已经发送...
第6封邮件已经发送...
第4封邮件已经发送...
第7封邮件已经发送...
第8封邮件已经发送...
发送第十封邮件
十个子进程是并发的,所以不一定谁先执行结束,所以不是顺序的。
(3)使用类的方法创建子进程
# (1) 基本语法
可以使用自定义的方式创建子进程,
但是必须继承父类Processs
而且所有的逻辑都必须写在run方法里面
#例:
from multiprocessing import Process import os class MyProcess(Process): # 必须使用叫做run的方法,而且()里面只能是self def run(self): # 写自定义的逻辑 print("子进程id>>>%s, 父进程的id>>>%s" % (os.getpid(), os.getppid())) if __name__ == "__main__": p = MyProcess() p.start() print("主进程:{}".format(os.getpid()))
输出结果为:
主进程:8236
子进程id>>>6412, 父进程的id>>>8236
# (2) 带参数的子进程函数
#例:
from multiprocessing import Process import os class MyProcess(Process): def __init__(self,arg): # 必须调用一下父类的初始化构造方法 super().__init__() self.arg = arg # 必须使用叫做run的方法 def run(self): # 在这里就得获取参数 print("子进程id>>>%s,父进程的id>>>%s" % (os.getpid(),os.getppid())) print(self.arg) if __name__ == "__main__": lst = [] for i in range(1,10): p = MyProcess("参数:%s" % (i)) p.start() lst.append(p) for i in lst: i.join() print("最后执行主进程的这句话...",os.getpid())
运行结果为:
子进程id>>>5964,父进程的id>>>5336
参数:2
子进程id>>>10544,父进程的id>>>5336
参数:3
子进程id>>>11512,父进程的id>>>5336
参数:4
子进程id>>>11160,父进程的id>>>5336
参数:5
子进程id>>>12068,父进程的id>>>5336
参数:1
子进程id>>>5288,父进程的id>>>5336
参数:6
子进程id>>>11380,父进程的id>>>5336
参数:8
子进程id>>>8092,父进程的id>>>5336
参数:7
子进程id>>>7120,父进程的id>>>5336
参数:9
最后执行主进程的这句话... 5336
结果分析:父进程是程序运行的主进程号不变,子进程是并发的所以那个参数先打印是不固定的,然后对每个子进程添加了join阻塞,所以没有全部执行完子进程之前,主进程的运行语句是不打印的,也就是在子进程join后主进程运行语句必须等待子进程全部结束才打印。