多进程multiprocessing——apply、map

目录

一、概述

二、实现

1.使用apply_async方法实现

2.使用map_async方法实现(一)

3.使用map_async方法实现(二)

三、BUG

四、参考


一、概述

pool:进程池,池中可以执行多任务进程

multiprocessing.Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None, context=None)
"""
参数介绍:
    processes: 设置要使用的进程数量,如果 processes 为 None,则使用 os.cpu_count() 返回的值
    initializer: 是每个工作进程启动时要执行的可调用对象,默认为None
    maxtasksperchild: 工作进程退出之前可以完成的任务数,完成后用一个新的工作进程来替代原进程,为了释放闲置资源
    context: 可被用于指定启动的工作进程的上下文
"""

pool中的任务分派方式

  • apply(func[, args[, kwds]])方法是阻塞,意味着当前的进程没有执行完的话,后续的进程需要等待该进程执行结束才能执行,实际上该方法是串行。
  • apply_async(func[, args[, kwds[, callback[, error_callback]]]])方法是异步非阻塞的,意味着不用等待当前进程执行完成,即可根据系统的调度切换进程,该方法是并行。
  • map(func, iterable[, chunksize])方法将iterable对象分成一些块,作为单独的任务提交给进程池。 这些块的(近似)大小可以通过将chunksize设置为正整数来指定, 并且该方法是阻塞的。如果可迭代对象很多时,会消耗较大的内存,可以考虑使用imap或imap_unordered。
  • map_async(func, iterable[, chunksize[, callback[, error_callback]]])方法是map的变种,是非阻塞的。

二、实现

1.使用apply_async方法实现

    (1)使用该方法并行时,需要依次传入参数,这就需要借助for循环等工具

for i in range(50):

        pool.apply_async(wrap, (result[i], ))

    (2)用.get()返回每个进程的返回值,但我在用这个方法获取返回值的时候,运算速度并没有提高。

"""
并行方法
"""
import time
import random

def bubbleSort(iList):
    '''冒泡排序 '''
    time.sleep(1)
    if len(iList) <= 1:
        return iList
    for i in range(1, len(iList)):
        ##外轮循环是为了确定最大的数
        # print('hhh',i)
        for j in range(0, len(iList) - i):
            if iList[j] >= iList[j + 1]:  # 比较相邻两数的大小
                iList[j], iList[j + 1] = iList[j + 1], iList[j]  # 将大数交换到靠后的位置
    return iList

def wrap(x):
    y = bubbleSort(x)
    List = []
    List.append(y)
    print("=======>",List)

if __name__ == '__main__':
    import multiprocessing

    #随机生成50个序列,每个序列100个元素
    result = list1 = [[0 for j in range(100)]for i in range(50)]
    for i in range(0, 50):

        for j in range(0, 100):  # 循环随机数100位
            result[i][j] = random.randint(0, 200)  # num得到随机数
            
    a = time.time()
    # 4为创建子进程的个数
    pool = multiprocessing.Pool(4)

    for i in range(50):

        pool.apply_async(wrap, (result[i], ))

    pool.join()
    pool.close()
    print("主进程结束")

    b = time.time()
    time = b - a
    print(time)

2.使用map_async方法实现(一)

    该方法将pool命令写在了“__main__”里。

(1)使用该方法传参数时,将iterable的每个元素作为参数,应用func函数。

(2)使用.get()返回结果,返回值是List的所有进程的结果。(单个元素的类型是输入数据的类型,仅由List类型进行包裹)

"""
并行方法
"""
import time
import random

def bubbleSort(iList):
    '''冒泡排序 '''
    print("i am running:")
    time.sleep(1)
    # List = []
    if len(iList) <= 1:
        return iList
    for i in range(1, len(iList)):
        ##外轮循环是为了确定最大的数
        # print('hhh',i)
        for j in range(0, len(iList) - i):
            if iList[j] >= iList[j + 1]:  # 比较相邻两数的大小
                iList[j], iList[j + 1] = iList[j + 1], iList[j]  # 将大数交换到靠后的位置
    return iList

def wrap(x):

    y = bubbleSort(x)
    print("y:",y)

if __name__ == '__main__':
    import multiprocessing

    #随机生成50个序列,每个序列100个元素
    list = [[0 for j in range(100)]for i in range(50)]
    for i in range(0, 50):

        for j in range(0, 100):  # 循环随机数100位
            list[i][j] = random.randint(0, 200)  # num得到随机数

    a = time.time()

    # 4为创建子进程的个数
    pool = multiprocessing.Pool(4)

    # for i in range(50):
    # print(result[0])
    result = pool.map_async(bubbleSort, list).get()
    print(result)
    # print(result)

    pool.close()
    pool.join()
    print("主进程结束")

    b = time.time()
    time = b - a
    print(time)

3.使用map_async方法实现(二)

    该方法将pool命令写在了函数里,但是注意:不管卸载哪里,都需要从“__main__”中触发并行,也就是,需要从“__main__”中运行。

"""
并行方法
"""

import random
import multiprocessing


def bubbleSort(iList):
    import time
    '''冒泡排序 '''
    print("i am running:")
    time.sleep(1)
    # List = []
    if len(iList) <= 1:
        return iList
    for i in range(1, len(iList)):
        ##外轮循环是为了确定最大的数
        # print('hhh',i)
        for j in range(0, len(iList) - i):
            if iList[j] >= iList[j + 1]:  # 比较相邻两数的大小
                iList[j], iList[j + 1] = iList[j + 1], iList[j]  # 将大数交换到靠后的位置

    return iList

def wrap(x):
    import time

    a = time.time()

    # 4为创建子进程的个数
    pool = multiprocessing.Pool(4)

    result = pool.map_async(bubbleSort, list).get()

    pool.close()
    pool.join()
    print("主进程结束")

    b = time.time()
    time = b - a
    print(time)
    return result

def wrap_1(x):
    y = wrap(x)
    return y

def wrap_2(x, a, b):
    c = a + b
    print("c:",c)
    y = wrap_1(x)
    print("y:",y)

if __name__ == '__main__':

    # 随机生成50个序列,每个序列100个元素
    list = [[0 for j in range(100)] for i in range(50)]
    for i in range(0, 50):

        for j in range(0, 100):  # 循环随机数100位
            list[i][j] = random.randint(0, 200)  # num得到随机数
    wrap_2(list, a=1, b=2)

三、BUG

使用GPU运行时可能会报以下错误:

1.RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method

2.RuntimeError: context has already been set

根据以上报错,在创建pool之前加入以下代码,即可成功运行

torch.multiprocessing.set_start_method( spawn , force=True)

四、参考

python并行计算(完结篇):并行方法总结

你可能感兴趣的:(Python,服务器,linux,python)