python 进程 笔记

一、进程

现实生活中,很多场景中的事情是同时进行的,比如开车的时候是手和脚共同来驾驶汽车;再比如唱歌和跳舞也是同时进行的,试想如果唱歌和跳舞分开来做的话就不会有那么好的效果了

程序中,如下,来模拟唱歌和跳舞;

很显然,刚才的程序并没有实现唱歌和跳舞同时进行;如果要实现‘跳舞和唱歌’同时进行,那么就需要一个新方法,叫做多任务

多任务的概念:

简单来说,操作系统可以同时运行多个任务,打个比方,你一边用浏览器上网,一边用播放器听音乐,一边用word赶作业,这就是多个任务,至少有3个任务在运行,后台还有好多任务在同时运行,只是桌面没有显示而已。

过去都是单核CPU,单核CPU也可以执行多任务,由于CPU执行代码都是顺序执行的,那么单核CPU是怎么执行多任务的呢?

答案就是操作系统轮流让各个任务交替运行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,切换到任务3...这样反复执行下去,表面上看每个任务都是交替执行的,但是由于CPU执行速度太快了,我们感觉就像所有的任务在同时执行一样。

真正的并行执行多任务只能在多核CPU上实现,但是由于任务量远远大于CPU的核数,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

1、进程的创建--fork()

进程 VS程序:

编写完的代码,在没有运行的时候,称之为程序。

正在运行的代码,称为进程

进程,除了包含代码以外,还有需要运行的环境等,是和程序有区别的。

fork()

python 的os模块封装了常见的系统调用,其中就包括fork,可以在python进程中轻松创建子进程;

说明:

程序执行到os.fork()时,操作系统会创建一个新的进程(子进程),然后复制父进程的所有信息到子进程中

然后父进程和子进程都会从fork()函数中得到一个返回值,在子进程中这个值一定为0,而父进程的这个值为子进程的ID号

getpid()、getppid()

2、多进程修改全局变量

多进程中,每个进程中所有数据(包括全局变量)都会各拥有一份,互不影响

3、多次fork 问题

如果在一个程序中,有两次fork函数调用,会产生几个进程

答案是每fork调用一次,会产生2的x次方个进程

调用一次fork产生两个进程,一个父进程,一个子进程;

调用两次fork,会产生4个进程,如下图:

父子进程的执行顺序

父进程和子进程执行顺序没有规律,完全取决于操作系统的调度算法。

4、multiprocessing

windows上没有fork调用,难道在Windows上无法用python编写多进程的程序?

multiprocessing模块就是跨平台版本的多进程模块

multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子来演示了启动一个进程并等待其结束:

说明:

创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,

join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步;

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值;

实例1:

运行结果:

实例2:

运行结果:

5、进程的另一种创建方法

进程的创建-Process子类
创建新的进程还能使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同实例化一个进程对象,请看下面实例:

 

说明:

对一个不包含target属性的Process类,执行start()方法,就会运行这个类中的run方法;

6、进程池

当需要创建的⼦进程数量不多时, 可以直接利⽤multiprocessing中的Process
动态成⽣多个进程, 但如果是上百甚⾄上千个⽬标, ⼿动的去创建进程的⼯
作量巨⼤, 此时就可以⽤到multiprocessing模块提供的Pool⽅法。
初始化Pool时, 可以指定⼀个最⼤进程数, 当有新的请求提交到Pool中时,
如果池还没有满, 那么就会创建⼀个新的进程⽤来执⾏该请求; 但如果池中
的进程数已经达到指定的最⼤值, 那么该请求就会等待, 直到池中有进程结
束, 才会创建新的进程来执⾏, 请看下⾯的实例:

multiprocessing.Pool常用函数解析:

apply_async(func[args[,kwds]]):使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字列表;

apply(func[args[,kwds]]):使用阻塞方式调用func;

close():关闭进程池,使其不再接收新的任务;

terminate():不管任务是否完成,立即终止

join():主进程阻塞,等待子进程退出,必须要在close()或terminate()之后使用;

7、进程间通信

Process间有时需要通信

可以使用multiprocessing 模块的Queue实现多进程之间的的数据传递,Queue本身是一个消息队列程序;

Queue使用说明:

初始化Queue()对象时,(例如:q = Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接收的消息数量没有上线(直到内存的上限);

Queue.qsize():返回当前队列包含的消息数量;

Queue.empty():如果队列为空,返回True,反之false;

Queue.full():如果队列满了,返回True,反之false;

Queue.get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,block默认值为True;

1)、如果block为默认值True,且没有设置timeout(单位秒)时间,消息队列如果为空,此时程序将被阻塞(停在读取状态),直到从消息队列读到消息为止;

如果设置了timeout,则会等待timeout秒,如还没有读取到消息,则抛出‘Queue.Empty ’异常;

2)、如果block 为false,消息队列如果为空,则会立刻抛出‘Queue.Empty’异常;

Queue.get_nowait():相当于Queue.get(False);

Queue.put(item,[block[,timeout]]):将item写入队列,block默认为True;

1)、如果block为默认值True,且没有设置timeout(单位秒)时间,如果消息队列没有空间写入,此时程序将被阻塞(停在写入状态),直到从消息队列腾出空间为止,;

如果设置了timeout,则会等待timeout秒,如还没有写入空间,则抛出‘Queue.Full ’异常;

2)、如果block 为false,消息队列没有写入空间,则会立刻抛出‘Queue.Full’异常;

Queue.put_nowait(item): 相当于 Queue.put(item,False)

实例:

在父进程中创建两个子进程,一个往Queue中写数据,一个从Queue中读数据;

进程池中的Queue:

如果要使用Pool创建进程,就需要使用 multiprocessing.Manager()中的Queue()

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值