流畅的Python阅读笔记(二)——python多进程

python多进程

在Python中,如果希望借助计算机多核的优势提高程序的运行效率,往往必须借助多进程来实现。因为在Python中,单一进程运行时会有一个GIL全局锁,每个线程在切换时都必须获取这个锁来取得CPU的控制权,因此Python中的多线程程序是线程安全的,但是往往很难发挥出并行计算的优势。一般只有在进行IO密集型的程序时才能够发挥出效率优势。在CPU密集的程序中,往往采用多进程的方式来提高效率。

multiprocessing

multiprocessing是一个最为常见的多进程python包,这是一个python内置的标准库,不需要额外下载。这个类库的基本用法如下:

import multiprocessing

def func(arg1, arg2):
    pass

def back(res):
    pass

def process():
    arg1 = ''
    arg2 = ''
    process_num = 4
    lock = multiprocessing.Lock()
    pool = multiprocessing.Pool(process_num)
    for i in range(10):
        pool.apply_async(func, (arg1, arg2,), callback=back)
    print "hello world!"
    pool.close()
    pool.join()
    print "begin main"

上述是multiprocessing模块的一个基本用法,其中func是需要并行执行的函数,back是回调函数,在func执行完后,对func的返回值进行处理。arg1和arg2是函数的两个参数。pool是multiprocessing模块中的进程池,这个进程池会维持指定数量的进程,在之前的进程完成后,将还未完成的进程添加进进程池。lock是进程锁,在读写一些需要上锁的文件或者数据库时需要使用。

pool在添加进程时有两个函数添加,一个是apply(),一个是apply_async(),这两者的区别在于,前者是阻塞的,即子进程未运行完时,主进程的内容不会运行。而后者是非阻塞的,子进程即使未运行完,主进程仍然会继续执行。

pool的close方法执行后,将不能再往进程池中添加进程。在join方法执行后,主进程将会被阻塞,直到所有的子进程执行完后,才会继续执行主进程。

concurrent.futures

在《流畅的python》一书中,还提供了另外的一种实现多进程并发执行的方法。该方式使用concurrent.futures模块来实现多进程。这个模块同样也是内置的标准库模块,不需要额外下载便可以使用。

import concurrent.futures

def download_one(cc):  # <3>
    image = get_flag(cc)
    show(cc)
    save_flag(image, cc.lower() + '.gif')
    return cc

def download_many(cc_list):
    workers = 4
    with futures.ProcessPoolExecutor(workers) as executor:  # <5>
        res = executor.map(download_one, sorted(cc_list))  # <6>

    return len(list(res))  # <7>

上述模块的使用更加简单,map便是python中map函数的含义,只是在该模块中,map中的函数是平行执行的,并且将结果写入最后的结果中res中。

多进程的局限性

最近为了提高程序的运行效率,多次使用多进程进行开发,发现Python的多进程存在许多不足的地方。

内存

Python多进程程序是通过在操作系统中新建子进程来实现的,因此其运行效率与操作系统在进程管理方面的策略息息相关。在操作系统中,子进程除了代码段与父进程共享外,其他内存都是与独立于父进程的,因此在生成子进程时,会将父进程的资源进行全量拷贝。如果父进程占用了大量的内存,那么它的所有子进程也会占用大量的内存。因此,在使用多进程时需要尽可能降低父进程的内存占有,将文件读取等需要占有大量内存的操作放到子进程进行。

变量传递

在进行了多次试验后,我发现Python的父进程往子进程传递参数时,只能传递Python的内置变量类型,即只能传递值类型变量(数组、字典等内置变量能否传递未验证)。自己定义的一些类对象,以及C++对象都是不能传递到子进程中的。在使用子进程时遇到不用多进程可以执行,但是用多进程子进程便不执行的问题基本都是这个原因造成的。我目前解决这个问题的方法是借助临时文件来存储主进程处理好的数据,然后使用子进程读取这些临时文件,来进行并行处理。

变量共享

主进程与子进程是并发执行的,进程之间默认是不能共享全局变量的(子进程不能改变主进程中全局变量的值)。如果要共享全局变量需要用(multiprocessing.Value(“d”,10.0),数值)(multiprocessing.Array(“i”,[1,2,3,4,5]),数组)(multiprocessing.Manager().dict(),字典)(multiprocessing.Manager().list(range(5)))。进程通信(进程之间传递数据)用进程队列(multiprocessing.Queue(),单向通信),管道( multiprocessing.Pipe() ,双向通信)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值