zoukankan      html  css  js  c++  java
  • python 多进程

    python 多进程

    一、创建多进程的基本法方法

    创建进程的类:Process([group [, target [, name [, args [, kwargs]]]]]),target表示调用对象,args表示调用对象的位置参数元组。kwargs表示调用对象的字典。name为别名。group实质上不使用。

    1、使用现成的Process类创建多线程

    import multiprocessing
    import time
    
    def worker(interval):
        n = 5
        while n > 0:
            print("The time is {0}".format(time.ctime()))
            time.sleep(interval)
            n -= 1
    
    if __name__ == "__main__":
        p = multiprocessing.Process(target = worker, args = (3,))
        p.start()
        print "p.pid:", p.pid
        print "p.name:", p.name
        print "p.is_alive:", p.is_alive()
    输出结果:
    p.pid: 8736
    p.name: Process-1
    p.is_alive: True
    The time is Tue Apr 21 20:55:12 2015
    The time is Tue Apr 21 20:55:15 2015
    The time is Tue Apr 21 20:55:18 2015
    The time is Tue Apr 21 20:55:21 2015
    The time is Tue Apr 21 20:55:24 2015
    

    二、使用自定义的类创建多线程

    import multiprocessing
    import time
    
    class MyProcess(multiprocessing.Process):
        def __init__(self, interval):
            multiprocessing.Process.__init__(self)
            self.interval = interval
    
        def run(self):
            n = 5
            while n > 0:
                print("the time is {0}".format(time.ctime()))
                time.sleep(self.interval)
                n -= 1
    
    if __name__ == '__main__':
        p = MyProcess(3)
        p.start()      
    输出结果:
    the time is Wed Jul 20 22:44:16 2016
    the time is Wed Jul 20 22:44:19 2016
    the time is Wed Jul 20 22:44:22 2016
    the time is Wed Jul 20 22:44:25 2016
    the time is Wed Jul 20 22:44:28 2016
    

     

    说明:自定义多线程类需要重写run方法,执行自定义类的实例时会自动调用run方法。

    3、守护进程

    1)守护进程即守护主进程的进程,与主进程同生共死。

    2)主进程退出时,守护进程也跟着退出。

    3)默认情况下,创建的紫禁城程非守护进程,既主进程如果执行完毕的,而子进程没有执行完毕,主进程会等待子进程执行完毕后再退出。

    4)设置守护进程的方法是 setDaemon = True。

    def worker(interval):
        print("work start:{0}".format(time.ctime()));
        time.sleep(interval)
        print("work end:{0}".format(time.ctime()));
    
    if __name__ == "__main__":
        p = multiprocessing.Process(target = worker, args = (3,))
        p.daemon = True
        p.start()
        print("end!")
    输出结果:
    
    end!

    输出结果只有一个end!,子进程随着主进程的消亡而消亡,因为设置了守护进程。

    4、进程间共享数据

    默认情况下进程间不能共享数据

    #-*-coding:utf8-*-
    import multiprocessing
    li = []
    
    def foo(i):
        global li
        li.append(i)
        print('say hi', li)
    
    if __name__ == '__main__':
        for i in range(10):
            p = multiprocessing.Process(target=foo, args=(i,))
            p.start()
    
        print('ending', li)
    输出结果:
    say hi [1]
    say hi [0]
    say hi [2]
    say hi [3]
    say hi [4]
    say hi [5]
    ending []
    say hi [6]
    say hi [8]
    say hi [7]
    say hi [9]
    

    说明进程间没有共享数据

    进程间共享内存空间的方法

    方法一:使用multiprocess 自带的queues

    from multiprocessing import Process
    from multiprocessing import queues
    import multiprocessing
    
    def foo(i,arg):
        arg.put(i)
        print('say hi',i,arg.qsize())
    
    
    if __name__ == "__main__":
        # li = []
        li = queues.Queue(20,ctx=multiprocessing)
        for i in range(10):
            p = Process(target=foo,args=(i,li,))
            #p.daemon = True
            p.start()
            #p.join()
    输出结果:
    say hi 7 2
    say hi 6 3
    say hi 2 3
    say hi 5 4
    say hi 1 6
    say hi 3 6
    say hi 4 8
    say hi 0 8
    say hi 9 9
    say hi 8 10
    

    说明:从输出结果中可以看到 队列的大小是在不断变化的,从而说明各个进程进程建共享了队列的数据。

    方法二:使用multiprocessing的数据结构 Array

    from multiprocessing import Process
    from multiprocessing import Array
    
    def foo(i,arg):
        arg[i] = i + 100
        for item in arg:
            print(item)
        print('================')
    
    if __name__ == "__main__":
        li = Array('i', 3)
        for i in range(3):
            p = Process(target=foo,args=(i,li,))
            p.start()
    输出结果:
    0
    0
    102
    ================
    0
    101
    102
    ================
    100
    101
    102
    ================
    

    说明:默认情况下 Array 初始化状态下,是一组内存地址连续的,数据类型相同的,初始值是0的一组数据。我们看到在多个进程的的作用下,Array 不同位置的元素,被连续修改。说明多个进程建共享了内存。

    方法三:使用multiprocess的内置字典

    from multiprocessing import Process
    from multiprocessing import Manager
    import multiprocessing
    
    
    def foo(i,arg):
        arg[i] = i + 100
        print(arg.values())
    
    if __name__ == "__main__":
        obj = Manager()
        li = obj.dict()
        for i in range(10):
            p = Process(target=foo,args=(i,li,))
            p.start()
            p.join()
     
    输出结果:
    [100]
    [100, 101]
    [100, 101, 102]
    [100, 101, 102, 103]
    [100, 101, 102, 103, 104]
    [100, 101, 102, 103, 104, 105]
    [100, 101, 102, 103, 104, 105, 106]
    [100, 101, 102, 103, 104, 105, 106, 107]
    [100, 101, 102, 103, 104, 105, 106, 107, 108]
    [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
    

    说明:从输出结果上看,字典的值是不断增加的,说明多个进程间共享了字典的内存空间。

    进程池

    进程池会把进程的最大数量控制在一个值,进程池可以提供指定数量的进程供用户调用,当有新的请求提交到进程池中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果进程池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

    1、使用阻塞的进程池

    import multiprocessing
    import time
    
    def func(msg):
        print("msg:", msg)
        time.sleep(2)
        print("end")
    
    if __name__ == "__main__":
        pool = multiprocessing.Pool(processes=3)
        for i in range(5):
            msg = "mark %d" % i
            pool.apply(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
    
        print("proessed here ##################")
        pool.close()
        pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数使主进程阻塞,等待所有子进程结束
        print("done.")
    输出结果:
    msg: mark 0
    end
    msg: mark 1
    end
    msg: mark 2
    end
    msg: mark 3
    end
    msg: mark 4
    end
    proessed here ##################
    done.
    

    2、使用异步的进程池(非阻塞)

    import multiprocessing
    import time
    
    def func(msg):
        print("msg:", msg)
        time.sleep(2)
        print("end")
    
    if __name__ == "__main__":
        pool = multiprocessing.Pool(processes=3)
        for i in range(5):
            msg = "mark %d" % i
            pool.apply_async(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
    
        print("proessed here ##################")
        pool.close()
        pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数使主进程阻塞,等待所有子进程结束
        print("done.")
    输出结果:
    proessed here ##################
    msg: mark 0
    msg: mark 1
    msg: mark 2
    end
    msg: mark 3
    end
    msg: mark 4
    end
    end
    end
    done.
    

    相关函数说明:

    1、apply_async(func[, args[, kwds[, callback]]]) 

    与apply用法一致,但它是非阻塞的且支持结果返回后进行回调。

    主进程循环运行过程中不等待apply_async的返回结果,在主进程结束后,即使子进程还未返回整个程序也会退出。虽然 apply_async是非阻塞的,但其返回结果的get方法却是阻塞的,如使用result.get()会阻塞主进程。
    如果我们对返回结果不感兴趣, 那么可以在主进程中使用pool.close与pool.join来防止主进程退出。注意join方法一定要在close或terminate之后调用。

    2、close() 
    关闭pool,使其不再接受新的任务。

    3、terminate() 
    结束工作进程,不再处理未处理的任务。

    4、join() 
    主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。

    3、获取进程池中进程的返回结果

    import multiprocessing
    import time
    
    def func(msg):
        print("msg:", msg)
        time.sleep(3)
        print("end")
        return "done" + msg
    
    if __name__ == "__main__":
        pool = multiprocessing.Pool(processes=4)
        for i in range(5):
            msg = "hello %d" % i
            print(pool.apply_async(func, (msg,)).get())
        pool.close()
        pool.join()
    输出结果:
    msg: hello 0
    end
    donehello 0
    msg: hello 1
    end
    donehello 1
    msg: hello 2
    end
    donehello 2
    msg: hello 3
    end
    donehello 3
    msg: hello 4
    end
    donehello 4
    

    说明:我们看到,当获取进程池中进程的结果时,输出结果是阻塞的。正如上边apply_sync函数的解释,当要获取进程的结果时,执行的过程就会变成阻塞的。

  • 相关阅读:
    linux驱动程序之电源管理之标准linux休眠与唤醒机制分析(一)
    linux驱动程序之电源管理 之linux休眠与唤醒(2)
    linux驱动程序之电源管理之regulator机制流程 (1)
    ARM--存储管理器
    元朝皇帝列表 元朝历代皇帝简介
    linux下valgrind的使用概述
    linux之sort用法
    python的ftplib模块
    Python使用struct处理二进制(pack和unpack用法)
    Python使用struct处理二进制(pack和unpack用法)
  • 原文地址:https://www.cnblogs.com/9527chu/p/5690020.html
Copyright © 2011-2022 走看看