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

    多线程给我们的感觉

      1.因为GIL的存在,一个进程的多线程同一时刻只能进去一个,感觉是假的并发

      2.只适合I/O密集型的任务

      3.针对计算密集型,就挂了(变成串行了)

    在python中想要充分利用多核cpu的优势,就可用多进程这个技术---multiprocessing

            multiprocessing是多进程的一个管理包。包含 Process、Queue、Pipe、Lock等组件。与thread类似

      该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

    但在使用这些共享API的时候,我们要注意以下几点:

    • 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。
    • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
    • 多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

    简单的例子:

    from multiprocessing import Process
    import os
    def info(name):
        print(name)
        print(os.getppid())#在主进程运行的是的是这个是pychar的pid
        print(os.getpid())
    
    if __name__ == "__main__":
        info("main")
        p=Process(target=info,args=("bob",))
        p.start()
        p.join()
    View Code

    进程之间通讯

    1. Queue()  注意这个不同于进程queue。  每个进程之间使用pickle序列化实现

    2. Pipe()

    queue代码:注意q要当参数 传递给函数,不然无法使用。因为进程之间数据默认不共享的。

    from multiprocessing import Process, Queue
    
    def f(q,n):
        q.put([42, n, 'hello'])
    
    if __name__ == '__main__':
        q = Queue()
        p_list=[]
        for i in range(3):
            p = Process(target=f, args=(q,i))
            p_list.append(p)
            p.start()
        print(q.get())
        print(q.get())
        print(q.get())
        for i in p_list:
                i.join()
    View Code

    Pipe代码

    from multiprocessing import Process, Pipe
     
    def f(conn):
        conn.send([42, None, 'hello'])
        conn.close()
     
    if __name__ == '__main__':
        parent_conn, child_conn = Pipe()
        p = Process(target=f, args=(child_conn,))
        p.start()
        print(parent_conn.recv())   # prints "[42, None, 'hello']"
        p.join()
    View Code

    进程之间数据共享:Manager组件

    from multiprocessing import Process, Manager
    
    def f(d, l,n):
        d[n] = '1'
        d['2'] = 2
        d[0.25] = None
        l.append(n)
        print(l)
    
    if __name__ == '__main__':
        with Manager() as manager:
            d = manager.dict()
    
            l = manager.list(range(5))
            p_list = []
            for i in range(10):
                p = Process(target=f, args=(d, l,i))
                p.start()
                p_list.append(p)
            for res in p_list:
                res.join()
    
            print(d)
            print(l)
    View Code

        这里存在一个问题:数据共享 是不是要加锁

    进程之间的数据同步LOCK:

    用法与线程的一样:主要是为了防止进程抢占屏幕输出,避免输出错乱

    from multiprocessing import Process, Lock
    
    def f(l, i):
        l.acquire()
        try:
            print('hello world', i)
        finally:
            l.release()
    
    if __name__ == '__main__':
        lock = Lock()
    
        for num in range(10):
            Process(target=f, args=(lock, num)).start()
    View Code

     进程池:                                                                                                                                                     

    两种方法:
    • pool.apply
    • pool.apply_async
    from multiprocessing import Pool
    import os,time
    def Foo(i):
        time.sleep(2)
        print("子进程",i,os.getpid())
    def Bar(arg):
        print("Exec done",arg,os.getpid())
    if __name__=="__main__":
        pool = Pool(3) #已经启动了10个进程,但是同一时刻只能有3个进程执行
        for i in range(10):
            #pool.apply(func=Foo,args=(i,)) #串行效果
            #pool.apply_async(func=Foo,args=(i,))#异步方法,为了显示效果,必须加上,join。
            pool.apply_async(func=Foo, args=(i,),callback=Bar) #异步使用回调函数,但是这个回调是在主进程中执行的,列如:在数据库连接的时候,如果在子进程连接,每个都要打开新的,不好
        pool.close()
        pool.join()#join之前,必须加上close,注意:close在前。
    View Code
  • 相关阅读:
    [P1034][NOIP2001]一元三次方程求解 (二分)
    考前停课集训 Day7 嘞
    [P4995]跳跳!(贪心)
    [P4994]终于结束的起点 (递推)
    考前停课集训 Day6 垒
    [BZOJ1899][ZJOI2004]Lunch 午餐 (DP)
    考前停课集训 Day5 累
    任务查询系统 【主席树】
    主席树入门
    HNOI2002 营业额统计 平衡树模板题 【splay】
  • 原文地址:https://www.cnblogs.com/louhui/p/7967029.html
Copyright © 2011-2022 走看看