zoukankan      html  css  js  c++  java
  • python创建进程的常用方式

      运行程序时,单线程或单进程往往是比较慢的,为加快程序运行速度,我们可以使用多进程,可以理解为多任务同时运行,小编的电脑是四核,所以可以设置四个进程。

    下面,我们来了解下多进程的使用:

    1、使用multiprocessing模块创建进程

      multiprocessing模块提供了一个Process类来代表进程对象,语法如下:

      Process([group[,target[,name[,args[,kwargs]]]]])

      其中,group:参数未使用,值始终是None

      target:表示当前进程启动时执行的可调用对象

      name:为当前进程实例的别名

      args:表示传递给target函数的参数元组

      kwargs:表示传递给target函数的参数字典

    使用多进程的一个简单例子:

    from multiprocessing import Process     # 导入模块
    
    # 执行子进程代码
    def test(interval):
        print('我是子进程')
    # 执行主程序
    def main():
        print('主进程开始')
        # 实例化Procss进程类
        p = Process(target=test,args=(1,))
        # 启动子进程
        p.start()
        print('主进程结束')
    
    if __name__ == '__main__':
        main()

    结果:

    主进程开始
    主进程结束
    我是子进程

      Process的实例p常用的方法除start()外,还有如下常用方法:

      is_alive():判断进程实例是否还在执行

      join([timeout]):是否等待进程实例执行结束,或等待多少秒

      start():启动进程实例(创建子进程)

      run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法

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

      Process类还有如下常用属性:

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

      pid:当前进程实例的PID值

    下面是Process类方法和属性的使用,创建两个子进程,分别使用os模块和time模块输出父进程和子进程的id以及子进程的时间,并调用Process类的name和pid属性:

    # -*- coding:utf-8 -*-
    from multiprocessing import Process
    import time
    import os
    
    #两个子进程将会调用的两个方法
    def  child_1(interval):
        print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
        # 计时开始
        t_start = time.time()
        # 程序将会被挂起interval秒
        time.sleep(interval)
        # 计时结束
        t_end = time.time()
        print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))
    
    def  child_2(interval):
        print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
        # 计时开始
        t_start = time.time()
        # 程序将会被挂起interval秒
        time.sleep(interval)
        # 计时结束
        t_end = time.time()
        print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))
    
    if __name__ == '__main__':
        print("------父进程开始执行-------")
        # 输出当前程序的ID
        print("父进程PID:%s" % os.getpid())
        # 实例化进程p1
        p1=Process(target=child_1,args=(1,))
        # 实例化进程p2
        p2=Process(target=child_2,name="mrsoft",args=(2,))
        # 启动进程p1
        p1.start()
        # 启动进程p2
        p2.start()
        #同时父进程仍然往下执行,如果p2进程还在执行,将会返回True
        print("p1.is_alive=%s"%p1.is_alive())
        print("p2.is_alive=%s"%p2.is_alive())
        #输出p1和p2进程的别名和PID
        print("p1.name=%s"%p1.name)
        print("p1.pid=%s"%p1.pid)
        print("p2.name=%s"%p2.name)
        print("p2.pid=%s"%p2.pid)
        print("------等待子进程-------")
        # 等待p1进程结束
        p1.join()
        # 等待p2进程结束
        p2.join()
        print("------父进程执行结束-------")

    结果:

    ------父进程开始执行-------
    父进程PID:13808
    p1.is_alive=True
    p2.is_alive=True
    p1.name=Process-1
    p1.pid=13360
    p2.name=mrsoft
    p2.pid=21500
    ------等待子进程-------
    子进程(13360)开始执行,父进程为(13808)
    子进程(21500)开始执行,父进程为(13808)
    子进程(13360)执行时间为'1.01'秒
    子进程(21500)执行时间为'2.00'------父进程执行结束-------

      上述代码中,第一次实例化Process类时,会为name属性默认赋值为Process-1,第二次则默认为Process-2,但由于实例化进程p2时,设置了name属性为mrsoft,所以p2.name的值为mrsoft。

    2、使用Process子类创建进程

      对于一些简单的小任务,通常使用Process(target=test)方式实现多进程。但如果要处理复杂任务的进程,通常定义一个类,使其继承Process类,下面是通过使用Process子类创建多个进程。

    # -*- coding:utf-8 -*-
    from multiprocessing import Process
    import time
    import os
    
    #继承Process类
    class SubProcess(Process):
        # 由于Process类本身也有__init__初识化方法,这个子类相当于重写了父类的这个方法
        def __init__(self,interval,name=''):
            # 调用Process父类的初始化方法
            Process.__init__(self)
            # 接收参数interval
            self.interval = interval
            # 判断传递的参数name是否存在
            if name:
                # 如果传递参数name,则为子进程创建name属性,否则使用默认属性
                self.name = name        
        #重写了Process类的run()方法
        def run(self):
            print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
            t_start = time.time()
            time.sleep(self.interval)
            t_stop = time.time()
            print("子进程(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))
    
    if __name__=="__main__":
        print("------父进程开始执行-------")
        # 输出当前程序的ID
        print("父进程PID:%s" % os.getpid())                  
        p1 = SubProcess(interval=1,name='mrsoft')
        p2 = SubProcess(interval=2)
        #对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,
        #所以这里会执行p1.run()
        # 启动进程p1
        p1.start()
        # 启动进程p2
        p2.start()  
        # 输出p1和p2进程的执行状态,如果真正进行,返回True,否则返回False
        print("p1.is_alive=%s"%p1.is_alive())
        print("p2.is_alive=%s"%p2.is_alive())
        #输出p1和p2进程的别名和PID
        print("p1.name=%s"%p1.name)
        print("p1.pid=%s"%p1.pid)
        print("p2.name=%s"%p2.name)
        print("p2.pid=%s"%p2.pid)
        print("------等待子进程-------")
        # 等待p1进程结束
        p1.join()
        # 等待p2进程结束
        p2.join() 
        print("------父进程执行结束-------")

    结果:

    ------父进程开始执行-------
    父进程PID:2512
    p1.is_alive=True
    p2.is_alive=True
    p1.name=mrsoft
    p1.pid=20328
    p2.name=SubProcess-2
    p2.pid=13700
    ------等待子进程-------
    子进程(20328) 开始执行,父进程为(2512)
    子进程(13700) 开始执行,父进程为(2512)
    子进程(20328)执行结束,耗时1.00秒
    子进程(13700)执行结束,耗时2.00秒
    ------父进程执行结束-------

      上述代码中,定义了一个SubProcess子类,继承multiprocess.Process父类。SubProcess子类中定义了两个方法:__init__()初始化方法和run()方法,在__init__()初始化方法中,调用父类multiprocess.Process的__init__()初始化方法,否则父类的__init__()方法会被覆盖,无法开启进程。此外,在SubProcess子类中没有定义start()方法,但在主程序中却调用了start()方法,此时就会自动执行SubProcess类的run()方法。

    3、使用进程池Pool创建进程

      上面我们使用Process类创建了两个进程,但如果要创建十几个或者上百个进程,则需要实例化更多的Process类,解决这一问题的方法就是使用multiprocessing模块提供的pool类,即Pool进程池。

      我们先来了解下Pool类的常用方法:

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

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

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

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

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

      下面通过一个示例演示一下如何通过进程池创建多进程,设置最大进程数为3,使用非阻塞方式执行10个任务:

    # -*- coding=utf-8 -*-
    from multiprocessing import Pool
    import os, time
    
    def task(name):
        print('子进程(%s)执行task %s ...' % ( os.getpid() ,name))
        # 休眠1秒
        time.sleep(1)       
    
    if __name__=='__main__':
        print('父进程(%s).' % os.getpid())
        # 定义一个进程池,最大进程数3
        p = Pool(3)        
        # 从0开始循环10次   
        for i in range(10):
            # 使用非阻塞方式调用task()函数 
            p.apply_async(task, args=(i,))    
        print('等待所有子进程结束...')
        # 关闭进程池,关闭后p不再接收新的请求
        p.close()
        # 等待子进程结束
        p.join()    
        print('所有子进程结束.')

    结果:

    父进程(3856).
    等待所有子进程结束...
    子进程(18872)执行task 0 ...
    子进程(11220)执行task 1 ...
    子进程(10140)执行task 2 ...
    子进程(18872)执行task 3 ...
    子进程(11220)执行task 4 ...
    子进程(10140)执行task 5 ...
    子进程(18872)执行task 6 ...
    子进程(11220)执行task 7 ...
    子进程(10140)执行task 8 ...
    子进程(18872)执行task 9 ...
    所有子进程结束.

  • 相关阅读:
    zepto源码--插入节点--学习笔记
    zepto源码--width,height--学习笔记
    zepto源码--$.map,$.each,$.grep--学习笔记
    zepto源码--isEmptyObject,isNumeric,inArray,trim--学习笔记
    zepto源码--filtered, contains,funcArg,setAttribute,className,deserializeVale--学习笔记
    zepto源码--qsa--学习笔记
    webstorm开发微信小程序
    第三方博客
    git最基础操作一
    vue-输入框change事件并获取值
  • 原文地址:https://www.cnblogs.com/xiao02fang/p/12950577.html
Copyright © 2011-2022 走看看