Python中的进程
1、单任务和多任务
- 单任务:一次做一件事件,前一件事情做完,才开始下一件事情
- 多任务:同时做多件事情,多件事情可以同时处理。
2、单核CPU的多任务
- 时间片:CPU执行时间分割成小段
3、并行和并发
- 并行:m个任务在m个处理器运算核心上执行
- 并发:m个任务在n个处理器运算核心上执行,m>n
4、程序和进程
- 程序:存放代码的可执行文件,静态的
- 进程:运行中的程序,进程需要相应的系统资源:内存、时间片、pid。动态的
5、fork
Python中的OS模块封装了常见的系统调用,可以使用OS模块中的fork()方法来创建新的进程
- fork只能在linux/unix系统中使用,windows中是不可以的
- 当程序执行os.fork()时,系统会创建出一个新的进程(子进程),然后复制父进程中的所有内容到子进程中。
- 父进程、子进程都会从fork()函数中得到一个返回值。
- 父进程,得到子进程的pid
- 子进程,得到返回值0
import os
def main():
pid = os.fork()
if pid > 0:
print("父进程---Hello")
elif pid == 0:
print("子进程---world")
if __name__ == "__main__":
main()
运行结果:
父进程---Hello
子进程---world
6、多进程中的全局变量
import os
import time
num = 10
# 全局变量在多进程中,每个进程拥有的数据(包括全局变量)各有一份,是互不相关的
# 在父进程中,我们通过global改变了全局变量num的值,但是在子进程中,还是之前没有改变的num的值
def sing():
global num
for temp in range(3):
print("----sing--num:%d---pid:%d--ppid:%d" % (num, os.getpid(), os.getppid()))
num += 1
time.sleep(1)
def dance():
for i in range(3):
print("------dance--num:%d--pid:%d,ppid:%d" % (num, os.getpid(), os.getppid()))
time.sleep(1)
def main():
pid = os.fork()
if pid > 0:
sing()
elif pid == 0:
dance()
if __name__ == "__main__":
main()
运行结果:
----sing--num:10---pid:32922--ppid:20979
------dance--num:10--pid:32927,ppid:32922
----sing--num:11---pid:32922--ppid:20979
------dance--num:10--pid:32927,ppid:32922
----sing--num:12---pid:32922--ppid:20979
------dance--num:10--pid:32927,ppid:32922
总结:
在多进程中,每个进程中有的数据(包括全局变量),各有一份,在父进程中通过global改变了全局变量,在子进程中全局变量还是之前的值,不会改变。
父进程、子进程执行的顺序是没有规律的,完全取决于操作系统的调度算法
7、getpid和getppid
- os.getpid(): 获取当前进程的pid
- os.getppid(): 获取当前进程父进程的pid,即ppid
8、使用Process创建多进程
上面提到os.fork()不能在Windows下运行,那么既然说Python是一门跨平台的语言,那我们怎么在Windows平台下使用多进程呢?答案就是使用Process。
使用Process创建多进程的流程:
首先导入Process
form multiprocessing import Process
创建一个Process对象
p = Process() # 参数等会结合Demo讲解
启动进程
p.start() # 进程不启动,没有pid,但是会有进程名
结束进程
p.terminate()
p.join() # 导致父进程阻塞,等待子进程结束,并回收资源
创建Process对象时,可传递的参数:
p = Process(target=XXX, args=(元组), kwargs={key:value})
target = XXX 指定的任务函数
args = (元组) 、kwargs={key:value} 给任务函数传递的参数
判断进程是否在运行了
p.is_alive() # True表示在运行 False表示未运行
Demo
import os from multiprocessing import Process def myTask(): for i in range(5): print("子进程进程:%d --------%d" % (os.getpid(), i)) def main(): print("父进程:%d" % os.getpid()) # 创建一个进程 p = Process(target=myTask) # 启动进程 p.start() # 阻塞父进程,等待子进程结束,并回收哦资源 p.join() if __name__ == '__main__': main()
9、Process语法结构
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调用的对象
args:表示调用对象的位置参数元组
kwargs:表示 调用对象的关键字参数字典
name:为当前进程实例的别名
group:大多数情况下用不到
Process类的常用方法:
is_alive():判断进程实例是否还咋执行
join(timeout):是否等待进程实例执行结束,或等待多少秒
start():启动进程实例(创建子进程)
run():如果没有给定target参数,对这个对象调用start()方法,就将执行对象中的run()方法
terminate():不管任务是否完成,立即终止
Process类常用的属性:
name:当前进程实例别名,默认名为Process-N,N为从1开始递增的整数
pid:当前进程实例的Pid值
10、使用Process子类创建进程
这就关系到了之前的面向对象中的继承,我们来写程序,来使用 Process的子类来创建进程。
Demo:
import os
from multiprocessing import Process
import time
"""
Process类本身也有__init__方法,这个子类相当于重写了这个方法
但是这样有一个问题,我们并没有完全的初始化一个Process类,所以就不能从这个类中继承一些方法和属性
最好的方法就是在__init__方法中奖继承类本身传递给Process.__init__方法,完成初始化操作
"""
class MyProcess(Process):
def __init__(self):
Process.__init__(self)
def run(self):
"""要执行的任务代码写在run方法中"""
for i in range(5):
print("子进程:%d,正在运行。。。%d" % (os.getpid(), i))
time.sleep(1)
def main():
print("父进程:%d,正在运行。。。" % os.getpid())
p = MyProcess()
p.start()
p.join()
if __name__ == '__main__':
main()
运行结果:
父进程:16836,正在运行。。。
子进程:13432,正在运行。。。0
子进程:13432,正在运行。。。1
子进程:13432,正在运行。。。2
子进程:13432,正在运行。。。3
子进程:13432,正在运行。。。4