python 之进程篇

多线程给咱们的感受python

  1.由于GIL的存在,一个进程的多线程同一时刻只能进去一个,感受是假的并发数据库

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

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

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

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

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

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

  • 在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要当参数 传递给函数,否则没法使用。由于进程之间数据默认不共享的。ui

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
相关文章
相关标签/搜索