学习python的multiprocess

文档地址:https://docs.python.org/zh-cn/3.9/library/multiprocessing.html

在学习之前,首先了解了一下python的:
global interpreter lock – 全局解释器锁(CIL)
CPython 解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python bytecode。此机制通过设置对象模型(包括 dict 等重要内置类型)针对并发访问的隐式安全简化了 CPython 实现。给整个解释器加锁使得解释器多线程运行更方便,其代价则是牺牲了在多处理器上的并行性。

也就是说python本身是没法实现的多线程,但是可以创造多个子进程来绕过CIL锁实现并行计算。

文档中提出了Pool对象,提供了一种快捷的方法,赋予函数并行化处理一系列输入值的能力,可以将输入数据分配给不同进程处理(数据并行)

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

我基于这个样例,想探索一下并行计算带来的性能提升



from dataclasses import dataclass
from multiprocessing import Pool
import re
import time
lst=[1, 2, 3]
res=[]
def f(x):
    return x*x
def cal_time1():
    starttime=time.time()
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
    endtime=time.time()
    
    return endtime-starttime
def cal_time2():
    starttime=time.time()
    for i in lst:
        res.append(f(i))
    print(res)
    endtime=time.time()
    
    return endtime-starttime

if __name__ == '__main__':
    t1=cal_time1()
    t2=cal_time2()
    print("t1",t1)
    print("t2:",t2)
    if t1<t2:
        print("t1 win!")
    

结果:
学习python的multiprocess_第1张图片
看起来multiprocess中带来的效果远比单进程要弱,这大概是因为数据本来就少,且不同进程算完合并的时间成本远大于计算的开销,所以在这个例子上多线程的好处完全没体现出来。

通过组里工作的驱动,自己尝试把一个方法写成multiprocess版本,目前思路大致如下:
判断该方法中是否存在可以拆分成多组同时计算的可能,这其中不涉及前后结果依赖或者读写的问题,如果可以那么这个方法应该可以写multiprocess版本。
找到要被拆分的那个计算对象,然后利用自己写的拆分规则将结点拆分成多组。
将要并行计算的部分塞到一个函数里,然后塞到partial中,设置好除了被分组的数据外所有变量。
partial的用法可以参考这篇博客:https://blog.csdn.net/qq_33688922/article/details/91890142
简单来说就是将一个已经定义好的函数,以及该函数中不变的参数放到partial中,然后partial会返回一个新的函数,我们以后都使用这个函数就可以了。

最后利用Pool及imap函数将partial定义好的函数与被分组的数据对象传进去。
下面代码中的n_workers代表进程池中进程数量,如果为None,默认按照cpu数量来。
关于imap其实就是一旦有结果了就可以拿,而不必等到所有进程完成再一次性拿所有结果,且仍保留输入的顺序。

注意点:
1.要切割的变量需要是一个列表类型,否则会报错,所以我这里让nodes_nbrs外包了一个list
2.将要并行的那部分代码取出来作为一个单独的函数,如果要使用imap的话不能再用yield了(会报错),否则双重懒加载就没有意义了…

 if n_workers is not None:
        import random

        from functools import partial
        from multiprocessing import Pool

        _local_weighted_triangles_and_degree_iter_function = partial(
            _local_weighted_triangles_and_degree_iter_parallel,
            G=G,
            weight=weight,
            max_weight=max_weight,
        )
 		nodes_nbrs = list(nodes_nbrs)
        random.shuffle(nodes_nbrs)
        if len(nodes_nbrs) > n_workers * 30000:
            nodes_nbrs = split_len(nodes, step=30000)
        else:
            nodes_nbrs = split(nodes_nbrs, n_workers)
        with Pool(n_workers) as p:
            ret = p.imap(_local_weighted_triangles_and_degree_iter_function, nodes_nbrs)
            for r in ret:
                for x in r:
                    yield x
    else:

你可能感兴趣的:(python,学习)