Python中的多进程

多进程:

程序:是一个指令的集合

进程:正在执行的程序,或者说当你运行一个程序,你就启动了一个进程。

--编写完的代码,没有运行时称为程序,正在运行的代码,称为进程。

--程序是死的(静态的)进程是活的(动态的)

操作系统轮流让各个任务交替执行,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

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

例如:我们启动了QQ,QQ就是一个主进程,在QQ运行过程中,我们分别打开了三个(和A B C同学的)聊天窗口,这时 每个窗口就是属于主进程下的一个子进程,我们和每个同学聊天的数据都各有一份,互不影响。

#模拟多任务处理:一边唱歌,一边跳舞
from time import sleep
def sing():
    for i in range(5):
        print("唱歌")
        dance()
        sleep(1)
def dance():
    print("跳舞")
sing()

程序开始运行时,首先会创建一个主进程,在主进程下,我们可以创建新的进程(子进程),子进程依赖于主进程,如果主进程结束,程序会退出。(例如:QQ运行过程中(主进程)我们打开了和多位好友的聊天窗口(子进程),和他们聊天,这时如果直接退出QQ,聊天窗口也会消失。)

Python提供了非常好用的多进程包multiprocessing,借助这个包,可以轻松完成从单进程到并发执行的转换。

multiprocessing模块提供了一个Process类来创建一个进程对象。

(也就是说Process类中把进程对象该有的特征都写入了,有了Process类,方便我们创建进程对象)

Process(target,name,args)

参数介绍:

-target 表示调用对象,即子进程要执行的任务

-args 表示调用对象的位置参数元组

-name 子进程的名称

from multiprocessing import Process
def run(name):
    print("子进程运行中,name=%s"%name)
    print("子进程结束")
    # print(a)
if __name__ == '__main__':
    print("父进程启动")
    # a = 1000
    p=Process(target=run,args=('test',),name='pro-1')
    #"="右边是创建的子进程对象,p是该对象的引用  name='pro-1'可以不写,系统会默认起名: Process-n(是第几个子进程就叫-几)
    #target表示调用对象,args表示调用对象的位置参数元组
    #注意:元组中只有一个元素时结尾要加,
    print("子进程将要执行")
    p.daemon=True  #是否设置为守护进程(主进程结束,子进程也结束)(如果主进程结束,子进程还在运行,那么这个子进程叫孤儿进程)
    p.start()#此时子进程运行,CPU中主进程和子进程频繁做切换
    #在子进程执行时有个问题:在Windows上,子进程执行时会自动import启动它的这个文件(主进程),而在import的时候是会执行这些语句的,
    #这些语句中包含了创建一个子进程对象,因此会导致递归(无限创建子进程)
    print(p.name)
    p.join()#此处join()的作用:让主进程等子进程执行完再退出(因为程序执行过程中如果主进程退出,此时子进程未执行完,也会退出)
    print("主进程结束")
'''
if __name__=='__main__':说明
一个Python的文件(模块)有两种使用的方法,第一是直接作为程序执行,
第二是被其他Python模块导入(import)调用执行(模块重用)
因此if __name__=='__main__':的作用就是控制这两种情况执行代码的过程,__name__是内置变量,用于表示当前模块的名字
(如果当前的文件作为程序直接执行,那么此时它的__name__就是__main)也就是说
在if __name__=='__main__':下的代码只有在文件作为程序直接执行时才会执行,而import到其他程序中是不会执行的
在Windows上,子进程会自动import启动它的这个文件,而在import的时候是会执行这些语句的,如果不加if __name__=='__main__':
的话就会无线递归创建子进程,所以必须把创建子进程的部分用那个if判断保护起来
import的时候如果__name__不是__main__,就不会递归运行了
'''

Process类常用方法:

—p.start() 启动进程,并调用该子进程中的p.run()

—p.run() 进程启动时运行的方法,正是它去调用target指定的函数

—p.terminate() 强制终止进程p,不会进行任何清理操作(了解即可)

进程强制终止后,进程对象仍然存在,但是此时你却不能调(因为已经强制终止了,不能再用start()了),此时的进程对象也被称为僵尸进程。

例如:如果程序有个限制:进程1执行完后才能执行进程2,此时把进程1强制终止,那么进程2永远也不能执行了。

—p.is_alive() 如果p仍然运行,返回True.用来判断进程是否还在运行

—p.join([timeout]):主进程等待p终止,timeout是可选的超时时间

Process类常用属性:

name:当前进程实例别名,默认为Pricess-N,N为从1开始递增的整数;

pid:当前进程实例的PID值(也就是当前的一个进程号)(只要有一个进程执行,系统就会给它分配一个PID,是系统用来分辨不同的进程用的)

全局变量在多个进程中不共享,进程之间的数据是独立的,默认情况下互不影响。

from multiprocessing import Process
num=1
def run1():
    global num
    num+=5
    print("子进程1运行中,num=%d"%num)
def run2():
    global num
    num+=10
    print("子进程2运行中,num=%d"%num)
if __name__ == '__main__':
    print("主进程启动")
    p1=Process(target=run1)
    p2=Process(target=run2)
    print("子进程将要执行")
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("子进程结束")
#运行结果
主进程启动
子进程将要执行
子进程1运行中,num=6
子进程2运行中,num=11
子进程结束
1

创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象.

import multiprocessing,time
class ClockProcess (multiprocessing.Process):
    def run(self):#重写run()方法
        n=5
        while n>0:
            print(n)
            time.sleep(1)
            n-=1
if __name__ == '__main__':
    p=ClockProcess()
    p.start()#启动进程并调用run()方法
    p.join()

进程池:

进程池:用来创建多个进程

当需要创建的⼦进程数量不多时, 可以直接利⽤multiprocessing中的Process动态生成多个进程, 但如果是上百甚⾄上千个⽬标,⼿动的去创建进程的⼯作量巨⼤,此时就可以⽤到multiprocessing模块提供的Pool

初始化Pool时,可以指定⼀个最⼤进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建⼀个新的进程⽤来执⾏该请求,但如果池中的进程数已经达到指定的最⼤值,那么该请求就会等待,直到池中有进程结束才会创建新的进程来执⾏.

from multiprocessing import Pool
import random,time
def work(num):
    print(random.random()*num)
    time.sleep(3)
if __name__ == '__main__':
    po=Pool(3)#定义一个进程池,最大进程数为3 默认大小为CPU核数
    for i in range(10):
        po.apply_async(work,(i,))#apply_async选择要调用的目标,每次循环会用空出来的子进程去调用目标
    po.close()#进程池关闭之后不再接受新的请求
    po.join()#等待po中所有子进程结束,语法规定:必须放在close后面
#在多进程中,主进程一般用来等待,真正的任务都在子进程中执行

multiprocessing.Pool常⽤函数解析:

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

–apply(func[, args[, kwds]])(了解即可几乎不用) 使⽤阻塞⽅式调⽤func

–close():关闭Pool,使其不再接受新的任务;

–terminate():不管任务是否完成,⽴即终⽌;

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值