进程、线程篇(下)

多进程multiprocessing

multiprocessing是一个包,它支持使用与线程模块类似的API生成进程。多处理包提供了本地和远程并发性,通过使用子进程而不是线程有效地绕过了全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。它可以在Unix和Windows上运行

#Author:AZ
import multiprocessing
import time,threading

def thread_run():
    print(threading.get_ident())
def run(name):
    time.sleep(2)
    print("hello",name)
    t = threading.Thread(target=thread_run,)
    t.start()

if __name__ == '__main__':
    for i in range(10):
        p = multiprocessing.Process(target=run,args=("bob %s" %i,))
        p.start()

 为了显示所涉及的各个进程id,下面是一个扩展示例,getppid()获取父进程id,getpid()获取进程id,所有进程都有一个父进程

#Author:AZ

from multiprocessing import Process
import os


def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())#获取父进程ID(pycharm进程)      所有进程都有一个父进程
    print('process id:', os.getpid())#获取进程id
    print("\n\n")


def f(name):
    info('\033[31;1mcalled from child process function f\033[0m')
    print('hello', name)

if __name__ == '__main__':
    info('\033[32;1mmain process line\033[0m')
    p = Process(target=f, args=('bob',))
    p.start()
    # p.join()

 进程间通讯

不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

Queues

使用方法跟threading里的queue差不多

#Author:AZ
from multiprocessing import Process, Queue
import threading

def f(qq):
    qq.put([43,None,'hello'])#子进程q
    
if __name__ == '__main__':
    q = Queue()#父进程q,

    p = Process(target=f,args=(q,))
    p.start()
    print(q.get())
    p.join()

 注:这里的父进程和子进程是两个进程,子进程克隆父进程,

子进程通过pickl序列化传值,通过反序列化把值传给父进程, 另外,此处进程和线程不同,不是对同一进程的修改,而是两个进程间的值的传递。

Pipes

函数的作用是:返回一对由管道连接的连接对象,默认情况下管道是双工(双向)的。例如

#Author:AZ
from multiprocessing import Process, Pipe


def f(conn):
    conn.send([42, None, 'hello from child'])
    conn.send([42, None, 'hello from child2'])
    print("from parent:",conn.recv())
    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']"
    print(parent_conn.recv())  # prints "[42, None, 'hello']"
    parent_conn.send("张洋可好") # prints "[42, None, 'hello']"
    p.join()

 Pipe()返回的两个连接对象表示管道的两端。每个连接对象都有send()和recv()方法(以及其他方法)。

注意,如果两个进程(或线程)试图同时从管道的同一端读取或写入数据,管道中的数据可能会损坏。

当然,同时使用管道的不同端不会有进程损坏的风险。

Managers

manager()返回的manager对象控制一个服务器进程,该进程持有Python对象,并允许其他进程使用代理操作它们。

manager()返回的管理器将支持类型列表、dict、名称空间、锁、RLock、信号量、有界信号量、条件、事件、屏障、队列、值和数组,可以实现这些数据的共享。例如

#Author:AZ
from multiprocessing import Process,Manager
import os
def f(d,l):
    d[os.getpid()] = os.getpid()
    l.append(os.getpid())
    print(l)

print("=================================")
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))
            p.start()
            p_list.append(p)
            for res in p_list:#等待结果
                res.join()

            print(d)
            print(l)

 进程同步

使用进程锁(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()

  

 进程池

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

进程池中有两个方法:

  • apply     :进程同步传输
  • apply_async    :进程异步传输
#Author:AZ

from multiprocessing import Process,Pool,freeze_support
import time
import os

def Foo(i):
    time.sleep(2)
    print("in process",os.getpid())
    return i + 100

def Bar(arg):
    print('-->exec done:',arg,os.getpid())

if __name__ =='__main__':
    pool =Pool(processes=5) #允许同时放入5 个进程
    print("主进程",os.getpid())
    for i in range(10):
        pool.apply_async(func=Foo,args=(i,),callback=Bar)
        #callback=回调,
        # pool.apply(func=Foo, args=(i,)) #串行=同步传输
        # pool.apply_async(func=Foo, args=(i,)) #并行=异步传输
    print('end')

    pool.close()
    pool.join()#进程池中进程执行完毕后再关闭,
    # 如果注释 pool.join(),或把它放在close()函数之前,那么程序直接关闭。
 #导致一些程序还未执行完

 注:callback,回调功能,即是子进程执行完后,主进程回调程序,原因是主进程持续连接着服务器,而子进程在不断切换

  此功能可以用于在执行子进程备份数据后,写log日志模块等......

  另外,pool.join()必须在pool.close()执行后执行。

 

posted @ 2019-03-17 23:18  Dylan123  阅读(134)  评论(0)    收藏  举报