如何在AWS Lambda中模拟multiprocessing.Pool.map()?

时间:2019-05-27 16:46:46

标签: python amazon-web-services multiprocessing

AWS Lambda上的Python不支持this other question中所述的multiprocessing.Pool.map()。请注意,另一个问题是询问为什么它不起作用。这个问题有所不同,考虑到缺乏基础支持,我想问的是如何模拟功能。

另一个问题的答案之一就是以下代码:

# 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用户进行开发他们自己的解决方法。我希望我已经尽了自己的职责,将其提炼成一个明确的问题,并假定准备好了构建模块。

2 个答案:

答案 0 :(得分:2)

我能够将其用于我自己的测试。 我的代码基于此链接: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))

希望有帮助。

答案 1 :(得分:0)

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

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