【0911 | Day 31】并发编程之多进程
目录
一、操作系统介绍
产生原因:因为硬件处理、优化工作繁琐,就像我在网络编程中总结的一样,操作系统就像是个网工,所以程序员只需要将这些工作交给他们,然后直接享受操作系统带来的便利就行啦~
1.1 第一代计算机(1940~1955):真空管和穿孔卡片
-
特点
- 没有操作系统的概念
- 所有的程序设计都是直接操控硬件
-
优点
- 程序员在申请的时间段内独享整个资源,可以即时地调试自己的程序(有bug可以立刻处理)
-
缺点
- 浪费计算机资源,一个时间段内只有一个人用。
1.2 第二代计算机(1955~1965):晶体管和批处理系统
-
优点
- 批处理,节省了机时
-
缺点
-
整个流程需要人参与控制,将磁带搬来搬去
-
计算的过程仍然是:顺序计算 ---> 串行
-
程序员原来独享一段时间的计算机,现在必须被统一规划到一批作业中,等待结果和重新调试的过程都需要等同批次的其他程序都运作完才可以(这极大的影响了程序的开发效率,无法及时调试程序)
-
1.3 第三代计算机(1965~1980):集成电路芯片和多道程序设计
-
多道技术
-
产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。 -
空间上的复用:如内存中同时有多道程序
时间上的复用:复用一个cpu的时间片
- 强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行
-
1.4 第四代计算机(1980~至今):个人计算机
二、并发编程之多进程
2.1 什么是进程
进程即正在执行的一个过程或者一个任务,而负责执行任务则是cpu。
2.2 进程和程序的区别
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
需要强调的是:同一个程序执行两次,那也是两个进程,但可以做不同的事
2.3 并发与并行
- 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发(并行也属于并发)
- 并行:同时运行,只有具备多个cpu才能实现并行
2.4 开启子进程的方式
方式一
from multiprocessing import Process
import time
def task():
print('进程 start')
time.sleep(2)
print('进程 end')
--->单个子进程
if __name__ == '__main__':
p = Process(target=task)
# 告诉操作系统我要开子进程,告诉完了这行代码就算执行完了,接着往下走,具体操作系统什么时候开子,开多长时间跟你没关系。
p.start()
time.sleep(5)
print('主进程/父进程')
--->多个子进程
if __name__ == '__main__':
p = Process(target=task,args=('rocky',))
p2 = Process(target=task,args=('nick',))
# 告诉操作系统我要开子进程,告诉完了这行代码就算执行完了,接着往下走,具体操作系统什么时候开子,开多长时间跟你没关系。
p.start()
# 告诉操作系统我要开子进程,告诉完了这行代码就算执行完了,接着往下走,具体操作系统什么时候开子,开多长时间跟你没关系。
p2.start()
time.sleep(5)
print('主进程/父进程')
方式二
from multiprocessing import Process
import time
class Test(Process):
def __init__(self,sex):
super().__init__()
self.sex = sex
def run(self):
print(f'子进程的性别是{self.sex} start')
time.sleep(2)
print('子进程 end')
if __name__ == '__main__':
p = Test('女')
p.start() # 向操作系统 发送开启子进程的请求
print('主进程')
2.5 multiprocessing模块介绍
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。
from multiprocessing import Process
import time
x = 0
def task():
global x
x = 100
print('子进程的x修改为了{}'.format(x))
if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(5)
print(x)
子进程的x修改为了100
0
2.6 Process类的介绍
创建进程的类
Process(target=[调用的函数], args(参数1,参数2...), kwargs(参数1,参数2...))
#参数含义
1.target表示调用对象,即子进程要执行的任务
2.args表示调用对象的位置参数元组,args=(1,2,'egon',)
3.kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
#方法介绍
1.p.start():启动进程,并调用该子进程中的p.run()
2.p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
3.p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
#属性介绍
1.p.name:进程的名称
2.p.pid:进程的pid
Process类的使用
参考上文开启子进程的两种方式