进程的概念
进程:进程指的就是程序的运行过程,是一个动态的概念(程序的运行就是由操作系统控制硬件去运行应用程序的过程)
程序:程序就是一系列的代码文件,是一个静态的概念
进程是操作系统最核心的概念,研究进程就是在研究操作系统
操作系统发展史
批处理操作系统->分时操作系统—>multics—>unix—>minix->linux
第一代计算机(1940~1955):真空管和穿孔卡片
优点:程序员在申请的时间段内独享整个资源,可以即时地调试自己的程序(有bug可以立刻处理)
缺点:浪费计算机资源,一个时间段内只有一个人用。同一时刻只有一个程序在内存中,被cpu调用执行,比方说10个程序的执行,是串行的
第二代计算机(1955~1965):晶体管和批处理系统
优点:批处理系统,节省了机时
缺点:
1.整个流程需要人参与控制,将磁带搬来搬去
2.计算的过程仍然是顺序计算-》串行(一个程序运行结束,再运行下一个程序)
3.程序员原来独享一段时间的计算机,现在必须被统一规划到一批作业中,等待结果和重新调试的过程都需要等同批次的其他程序都运作完才可以(这极大的影响了程序的开发效率,无法及时调试程序)
第三代计算机(1965~1980):集成电路芯片和多道程序设计(IBM公司)
多道技术(多道技术是有操作系统去控制cpu的,实现了并发)
1.空间上的复用:将内存分为几部分,每个部分放入一个程序(内存空间之间相互隔离),这样,同一时间内存中就有了多道程序。
2.时间上的复用:多个进程共享cpu的时间,cpu来回切换支持多个程序运行
cup在多个进程/任务之间的快速切换
1.遇到io切换
2.占用时间过长也会切换
分时操作系统:
多个联机终端+多道技术
贝尔实验室计算机科学家Ken Thompson后来开发了unix系统,
后来,在1987年,出现了一个UNIX的小型克隆,即minix,用于教学使用。芬兰学生Linus Torvalds基于它编写了Linux
第四代计算机(1980~至今):个人计算机
进程的相关概念
并发:多个任务看起来是同时运行的
并行:多个任务是真正意义上的同时运行
串行:一个任务运行完毕后才能开启下一个任务然后运行
任务运行的三种状态
运行态:进程正常运行
阻塞态:进程为等待输入而阻塞(程序从硬盘读到内存)
就绪态:进程等待运行
提交任务的两种方式
1.同步:提交完一个任务之后等待任务结果后,再提交下一个任务
2.异步:提交完任务之后不等待任务结果,直接提交下一个任务
提高进程运行的效率,降低io,能从内存拿数据就不要从硬盘拿数据,能从本地拿数据,就不要从网络拿数据。
操作系统调用接口的方式
windows系统调用接口的方式:fork
linux系统调用接口的方式:CreateProcess
从multiprocessing模块中导入Process这个类,这个模块封装好后直接就解决了跨平台性的问题
开启进程的两种方式
操作系统每开启一个子进程会把父进程的数据拷贝一份给子进程,作为子进程开启的初始数据。进程开启之后,子进程与父进程互不影响
在linux系统中,子进程刚刚开启的那一刻,子进程的数据是跟父进程一模一样的
在windows中,子进程刚刚开启的那一刻,也会继承父进程的数据,但是初始化的数据并不是一模一样的
windows操作系统下 创建进程一定要在main内创建
因为windows下创建进程类似于模块导入的方式
会从上往下依次执行代码
linux系统中是直接将代码完整的拷贝一份
方式一:
from multiprocessing import Process # 从multiprocessing模块中导入Process这个类。这个模块封装好了直接就解决了跨平台性的问题
import os
import time
def task(n):
print("父进程:%s 自己进程:%s 正在运行" % (os.getppid(), os.getpid())) # os.getppid(), os.getpid() 父进程的id ,自己进程的id
time.sleep(n)
print("父进程:%s 自己进程:%s 正在运行" % (os.getppid(), os.getpid()))
if __name__ == "__main__": # 在windows系统下开启子进程必须在该命令下开启
p = Process(target=task, args=(3,)) # 把task任务丢到target这个对象里面去,传参args=(n,)传的必须是一个元组
p.start() # 通知操作系统开启子进程,异步
print("主", os.getpid())
父进程开启子进程的的过程:应用程序调用操作系统接口,操作系统先开辟一个内存空间,再拷贝父进程的数据,在新开辟的内存空间里面开启子进程。
这个过程需要经历的时间远远超过了父进程自己程序运行的时间,根据异步的原则,打印结果为:
主 28572
父进程:28572 自己进程:1128 正在运行
父进程:28572 自己进程:1128 正在运行
方式二:
引入面向对象的概念
from multiprocessing import Process
import os
import time
class Myprocess(Process):
def __init__(self, n):
super().__init__()
self.n = n
def run(self) -> None: # run是不能加参数的
print("父进程:%s 自己进程:%s 正在运行" % (os.getppid(), os.getpid())) # os.getppid(), os.getpid() 父进程的id 自己进程的id
time.sleep(self.n)
print("父进程:%s 自己进程:%s 正在运行" % (os.getppid(), os.getpid()))
if __name__ == "__main__": # 在windows系统下开启子进程必须在该命令下开启
p = Myprocess(3)
p.start() # 通知操作系统开启子进程,异步
print("主", os.getpid())
进程间的内存空间是隔离的代码演示
例1:
from multiprocessing import Process # 从multiprocessing模块中导入Process这个类。这个模块封装好了直接就解决了跨平台性的问题
import time
count = 100 # 主进程的值
def task():
global count # global可以将全局名称空间的不可变类型的值改成局部名称空间不可变类型的值
count = 0
if __name__ == "__main__": # 在windows系统下开启子进程必须在该命令下开启
p = Process(target=task)
p.start() # 通知操作系统开启子进程,异步
time.sleep(5)
print("主", count) # 主 100
进程对象的方法
例2(并行代码演示):
p.jion()可以让主进程等待子进程运行结束后再运行主进程。
from multiprocessing import Process
import os
import time
def task(n):
print(os.getpid())
time.sleep(n)
if __name__ == '__main__':
p1 = Process(target=task, args=(3,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(1,))
start = time.time()
p1.start() # 通知操作系统开启子进程
p2.start() # 通知操作系统开启子进程
p3.start() # 通知操作系统开启子进程
p1.join() # 3
p2.join() # 2
p3.join() # 1 并发同时运行,主进程等待,不影响子进程运行,时间为3.23秒
stop = time.time()
print(stop - start)
例2(串行代码演示):
from multiprocessing import Process
import os
import time
def task(n):
print(os.getpid())
time.sleep(n)
if __name__ == '__main__':
p1 = Process(target=task, args=(3,))
p2 = Process(target=task, args=(2,))
p3 = Process(target=task, args=(1,))
start = time.time()
p1.start() # 通知操作系统开启子进程
p1.join()
p2.start() # 通知操作系统开启子进程
p2.join()
p3.start() # 通知操作系统开启子进程
p3.join()
p1.join() # 3
p2.join() # 2
p3.join() # 1 串行,p1,p2,p3依次运行,运行完结束之后再运行下一个。统计时间为6.378838539123535
stop = time.time()
print(stop - start)
其他功能代码展示
from multiprocessing import Process
import os
import time
def task(n):
print(os.getpid())
time.sleep(n)
if __name__ == '__main__':
p1 = Process(target=task, args=(3,), name="进程1") # 在括号里面添加name= 可以直接改子进程的名字
p1.start()
print(p1.name, p1.pid) # 查看子进程的名字和id
print(p1.is_alive()) # 判端子进程是否存活 True
p1.terminate() # 告诉操作系统强制结束进程
time.sleep(0.01)
print(p1.is_alive())