zoukankan      html  css  js  c++  java
  • 进程篇

    多进程 multiprocessing模块

    multiprocessing模块提供了一个Process类来代表一个进程对象 

    from multiprocessing import Process
    import os
     
     
    def run_proc(name):
        # 子进程要执行的函数
        print('Run child process %s (%s)...' % (name, os.getpid())) # os.getpid()表示获得当前进程的pid
     
    if __name__=='__main__':
        print('Parent process %s.' % os.getpid()) # 打印父进程的pid
        p = Process(target=run_proc, args=('test',)) # 创建进程对象,参数结构和多线程一样
        print('Child process will start.')
        p.start() # 启动子进程
        p.join() # 阻塞等待子进程执行完毕
        print('Child process end.')
     注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。并且python不能再Windows下创建进程!

    并且在使用多进程的时候,最好是创建多少个进程?:和CPU核数相等

    默认的进程之间相互是独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能
    如果你能穿墙的话两边就都可以使用了
    使用了3种方法

    默认的进程无法进行数据共享

    import multiprocessing
    import time
    
    def func(msg):
            for i in range(4):
                print(msg)
                time.sleep(1)
    
    if __name__ == '__main__':
        p = multiprocessing.Process(target=func, args=("hello",))
        p.start()
        p.join()
        print("have done")

    使用特殊的数据类型,来进行穿墙:

    默认的进程之间相互是独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能
    如果你能穿墙的话两边就都可以使用了
    使用了3种方法
    
    
    第一种方法:
    
    #通过特殊的数据结构:数组(Array)
    
    from multiprocessing import Process,Array
    
    #创建一个只包含数字类型的数组(python中叫列表)
    #并且数组是不可变的,在C,或其他语言中,数组是不可变的,之后再python中数组(列表)是可以变得
    #当然其他语言中也提供可变的数组
    #在C语言中数组和字符串是一样的,如果定义一个列表,如果可以增加,那么我需要在你内存地址后面再开辟一块空间,那我给你预留多少呢?
    #在python中的list可能用链表来做的,我记录了你前面和后面是谁。   列表不是连续的,数组是连续的
    
    '''
    上面不是列表是“数组"数组是不可变的,附加内容是为了更好的理解数组!
    '''
    
    temp = Array('i', [11,22,33,44]) #这里的i是C语言中的数据结构,通过他来定义你要共享的内容的类型!点进去看~
    
    def Foo(i):
    temp[i] = 100 + i
    for item in temp:
    print(i,'------->',item)
    for i in range(3):
    p = Process(target=Foo,args=(i,))
    p.start()
    ##output

    0 -------> 100
    0 -------> 22
    0 -------> 33
    0 -------> 44
    1 -------> 100
    1 -------> 101
    1 -------> 33
    1 -------> 44
    2 -------> 100
    2 -------> 101
    2 -------> 102
    2 -------> 44

    第二种方法:
    #方法二:manage.dict()共享数据
    from multiprocessing import Process,Manager  #这个特殊的数据类型Manager

    manage = Manager()
    dic = manage.dict() #这里调用的时候,使用字典,这个字典和咱们python使用方法是一样的!

    def Foo(i):
    dic[i] = 100+i
    print(dic.values())

    for i in range(2):
    p = Process(target=Foo,args=(i,))
    p.start()
    p.join()
    ##output

    [100]
    [100, 101]

    OK那么问题来了,既然进程之间可以进行共享数据,如果多个进程同时修改这个数据是不是就会造成脏数据?是不是就得需要锁!

    进程的锁和线程的锁使用方式是非常一样的知识他们是用的类是在不同地方的

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from multiprocessing import Process, Array, RLock

    def Foo(lock,temp,i):
    """
    将第0个数加100
    """
    lock.acquire()#进程加锁,避免修改内存中相同数据被不同进程修改
    temp[0] = 100+i
    for item in temp:
    print(i,'----->',item)
    lock.release()

    lock = RLock()
    temp = Array('i', [11, 22, 33, 44])

    for i in range(5):
    p = Process(target=Foo,args=(lock,temp,i,))
    p.start()
    ##output

    0 -----> 100
    0 -----> 22
    0 -----> 33
    0 -----> 44
    1 -----> 101
    1 -----> 22
    1 -----> 33
    1 -----> 44
    2 -----> 102
    2 -----> 22
    2 -----> 33
    2 -----> 44
    3 -----> 103
    3 -----> 22
    3 -----> 33
    3 -----> 44
    4 -----> 104
    4 -----> 22
    4 -----> 33
    4 -----> 44

     进程池

    进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

    进程池中有两个方法:

    • apply
    • apply_async
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    #  Author: Jason Wang
    
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from  multiprocessing import Process,Pool
    import time
    
    def Foo(i):
        time.sleep(2)
        return i+100
    
    def Bar(arg):
        print(arg)
    
    pool = Pool(5) #创建一个进程池,初始化进程数为5
    # print(pool.apply(Foo,(1,)))#去进程池里去申请一个进程去执行Foo方法
    #101
    #print(pool.apply_async(func =Foo, args=(1,)).get())
    
    for i in range(10):
        pool.apply_async(func=Foo, args=(i,),callback=Bar)#为进程池中的进程注入func方法,这里有apply_async和apply两种方式,分别表示异步和同步
    
    print('end')
    pool.close()
    pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
    ##output
    end
    100
    103
    102
    101
    104
    105
    108
    106
    107
    109
    '''
    apply 主动的去执行
    pool.apply_async(func=Foo, args=(i,),callback=Bar) 相当于异步,当申请一个线程之后,执行FOO方法就不管了,执行完之后就在执行callback ,当你执行完之后,在执行一个方法告诉我执行完了
    callback 有

    close方法:说关闭进程池,至此,进程池中不在有进程可以接受任务。

      terminate和join是一对方法,表示的内容截然相反,执行terminate是结束当前进程池中的所有进程,不管值没执行完。join方法是阻塞主进程,等待子进程执行完毕,再继续执行主进程。需要注意的是:这两个方法都必须在close方法之后执行。当然我们也可以不执行这两个方法,那么子进程和主进程就各自执行各自的,无论执行到哪里,子进程会随着主进程的结束而结束。。。

    import time
    import multiprocessing
    def func(msg):
        print(msg,'*** in func')
        time.sleep(3)
    
    if __name__ == "__main__":
        #
        pool = multiprocessing.Pool(processes=5)
        for i in range(3):
            print(i)
            pool.apply_async(func, ("hello %d" %(i), ))
            #pool.apply(func, ("hello %d" %(i), ))
        pool.close()
        #pool.terminate() #结束工作进程,不在处理未完成的任务
        pool.join() #主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用
        print("have done.")
    ##output
    0
    1
    2
    hello 0 *** in func
    hello 1 *** in func
    hello 2 *** in func
    have done.
    multiprocessing Pool Code

    获取进程池中进程的执行结果:

    import multiprocessing
    import time
    
    def func(msg):
        print("msg : ", msg)
        time.sleep(3)
        print("end")
        return "multi_result : " + msg
    
    if __name__ == "__main__":
        pool = multiprocessing.Pool(processes=4)
        result = []
        for i in range(3):
            msg = "hello %d" %(i)
            multi_result = pool.apply_async(func, (msg, ))
            result.append(multi_result)
        pool.close()
        pool.join()
        for res in result:
            print(res.get())
        print("have done.")
    multiprocessing get result example Code

    参考文献:

        python进程池:http://www.cnblogs.com/kaituorensheng/p/4465768.html

        python多进程的使用示例:http://outofmemory.cn/code-snippet/2267/Python-duojincheng-multiprocessing-usage-example

          python的线程、进程和协程:http://www.cnblogs.com/wupeiqi/articles/5040827.html  

        python的内存共享:http://www.cnblogs.com/dkblog/archive/2011/03/14/1983250.html

        python的多进程编程:http://www.cnblogs.com/kaituorensheng/p/4445418.html 

  • 相关阅读:
    概念辨析:Spring中@AutoWired和@Bean的区别
    打牢基础知识,避免采坑
    golang服务端编程
    如何避免写bug的一些实例和技巧
    常见数学问题的解题思路
    App开发需要了解的基本技术
    vue项目webpack打包
    vue项目中使用lottie动画
    js函数-参数默认值
    powershell操作excel
  • 原文地址:https://www.cnblogs.com/jasonwang-2016/p/5663795.html
Copyright © 2011-2022 走看看