【问题标题】:How to emulate multiprocessing.Pool.map() in AWS Lambda?如何在 AWS Lambda 中模拟 multiprocessing.Pool.map()?
【发布时间】:2019-05-27 16:46:46
【问题描述】:

AWS Lambda 上的 Python 不支持 multiprocessing.Pool.map(),如 this other question 中所述。请注意,另一个问题是询问为什么它不起作用。这个问题是不同的,我在问如何在缺乏底层支持的情况下模拟功能。

另一个问题的答案之一给了我们这个代码:

# Python 3.6
from multiprocessing import Pipe, Process

def myWorkFunc(data, connection):
    result = None

    # Do some work and store it in result

    if result:
        connection.send([result])
    else:
        connection.send([None])


def myPipedMultiProcessFunc():

    # Get number of available logical cores
    plimit = multiprocessing.cpu_count()

    # Setup management variables
    results = []
    parent_conns = []
    processes = []
    pcount = 0
    pactive = []
    i = 0

    for data in iterable:
        # Create the pipe for parent-child process communication
        parent_conn, child_conn = Pipe()
        # create the process, pass data to be operated on and connection
        process = Process(target=myWorkFunc, args=(data, child_conn,))
        parent_conns.append(parent_conn)
        process.start()
        pcount += 1

        if pcount == plimit: # There is not currently room for another process
            # Wait until there are results in the Pipes
            finishedConns = multiprocessing.connection.wait(parent_conns)
            # Collect the results and remove the connection as processing
            # the connection again will lead to errors
            for conn in finishedConns:
                results.append(conn.recv()[0])
                parent_conns.remove(conn)
                # Decrement pcount so we can add a new process
                pcount -= 1

    # Ensure all remaining active processes have their results collected
    for conn in parent_conns:
        results.append(conn.recv()[0])
        conn.close()

    # Process results as needed

能否修改此示例代码以支持multiprocessing.Pool.map()

到目前为止我尝试了什么

我分析了上面的代码,没有看到要执行的函数的参数或数据,所以我推断它没有执行与multiprocessing.Pool.map()相同的功能。除了演示可以组装成解决方案的构建块之外,不清楚代码的作用。

这是一个“为我写代码”的问题吗?

在某种程度上是的。这个问题影响了成千上万的 Python 开发人员,如果我们所有人共享相同的代码,而不是强迫遇到这个问题的每个 SO 用户去开发,它将对世界经济更有效率,减少温室气体排放等。他们自己的解决方法。我希望我已经完成了我的职责,将其提炼成一个明确的问题,假定的构建块已准备就绪。

【问题讨论】:

    标签: python amazon-web-services multiprocessing


    【解决方案1】:

    我能够在我自己的测试中使用它。 我的代码基于此链接:https://aws.amazon.com/blogs/compute/parallel-processing-in-python-with-aws-lambda/

    NB1:您必须增加 lambda 函数的内存分配。使用默认的最小数量,多处理不会提高性能。我的帐户可以分配的最大值 (3008MB) 达到了以下数字。

    NB2:我在这里完全忽略了最大并行进程。我的用法没有太多要处理的元素。

    下面的代码,用法是:

    work = funcmap(yourfunction,listofstufftoworkon)
    yourresults = work.run()
    

    从我的笔记本电脑运行:

    jumper@jumperdebian[3333] ~/scripts/tmp  2019-09-04 11:52:30
    └─ $ ∙ python3 -c "import tst; tst.lambda_handler(None,None)"
    results : [(35, 9227465), (35, 9227465), (35, 9227465), (35, 9227465)]
    SP runtime : 9.574460506439209
    results : [(35, 9227465), (35, 9227465), (35, 9227465), (35, 9227465)]
    MP runtime : 6.422513484954834
    

    从 aws 运行:

    Function Logs:
    START RequestId: 075a92c0-7c4f-4f48-9820-f394ee899a97 Version: $LATEST
    results : [(35, 9227465), (35, 9227465), (35, 9227465), (35, 9227465)]
    SP runtime : 12.135798215866089
    results : [(35, 9227465), (35, 9227465), (35, 9227465), (35, 9227465)]
    MP runtime : 7.293526887893677
    END RequestId: 075a92c0-7c4f-4f48-9820-f394ee899a97
    

    这是测试代码:

    import time
    from multiprocessing import Process, Pipe
    import boto3
    
    class funcmap(object):
    
        fmfunction=None
        fmlist=None
    
        def __init__(self,pfunction,plist):
            self.fmfunction=pfunction
            self.fmlist=plist
    
        def calculation(self, pfunction, pload, conn):
            panswer=pfunction(pload)
            conn.send([pload,panswer])
            conn.close()
    
        def run(self):
            datalist = self.fmlist
            processes = []
            parent_connections = []
            for datum in datalist:
                parent_conn, child_conn = Pipe()
                parent_connections.append(parent_conn)
                process = Process(target=self.calculation, args=(self.fmfunction, datum, child_conn,))
                processes.append(process)
    
            pstart=time.time()
            for process in processes:
                process.start()
                #print("starting at t+ {} s".format(time.time()-pstart))
            for process in processes:
                process.join()
                #print("joining at t+ {} s".format(time.time()-pstart))
    
            results = []
            for parent_connection in parent_connections:
                resp=parent_connection.recv()
                results.append((resp[0],resp[1]))
            return results
    
    
    def fibo(n):
        if n <= 2 : return 1
        return fibo(n-1)+fibo(n-2)
    
    def lambda_handler(event, context):
        #worklist=[22,23,24,25,26,27,28,29,30,31,32,31,30,29,28,27,26,27,28,29]
        #worklist=[22,23,24,25,26,27,28,29,30]
        worklist=[30,30,30,30]
        #worklist=[30]
        _start = time.time()
        results=[]
        for a in worklist:
            results.append((a,fibo(a)))
        print("results : {}".format(results))
        _end = time.time()
        print("SP runtime : {}".format(_end-_start))
    
        _mstart = time.time()
        work = funcmap(fibo,worklist)
        results = work.run()
        print("results : {}".format(results))
        _mend = time.time()
        print("MP runtime : {}".format(_mend-_mstart))
    

    希望对你有帮助。

    【讨论】:

    • 当任务执行外部阻塞调用(如数据库或 Web 服务)时,性能提升巨大。在单核上执行纯计算时预计不会有任何收益。
    【解决方案2】:

    我遇到了同样的问题,最终实现了我自己的简单包装器,围绕multiprocessing.Pool。绝对不是防弹的,但对于简单的用例来说已经足够了。

    https://stackoverflow.com/a/63633248/158049

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-02
      • 1970-01-01
      • 2023-01-31
      • 2022-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多