在python中同时并行化不同的函数

时间:2016-07-02 12:02:48

标签: python multithreading parallel-processing subprocess

我想同时执行f1和f2。但是下面的代码不起作用!

from multiprocessing import Pool

def f1(x):
return x*x

def f2(x):
return x^2

if __name__ == '__main__':

    x1=10
    x2=20
    p= Pool(2)
    out=(p.map([f1, f2], [x1, x2]))

y1=out[0]
y2=out[1]

2 个答案:

答案 0 :(得分:2)

我相信您希望在代码中使用threading.Threadshared queue

from queue import Queue
from threading import Thread
import time

def f1(q, x):
    # Sleep function added to compare execution times.
    time.sleep(5)
    # Instead of returning the result we put it in shared queue.
    q.put(x * 2)

def f2(q, x):
    time.sleep(5)
    q.put(x ^ 2)

if __name__ == '__main__':
    x1 = 10
    x2 = 20
    result_queue = Queue()

    # We create two threads and pass shared queue to both of them.
    t1 = Thread(target=f1, args=(result_queue, x1))
    t2 = Thread(target=f2, args=(result_queue, x2))

    # Starting threads...
    print("Start: %s" % time.ctime())
    t1.start()
    t2.start()

    # Waiting for threads to finish execution...
    t1.join()
    t2.join()
    print("End:   %s" % time.ctime())

    # After threads are done, we can read results from the queue.
    while not result_queue.empty():
        result = result_queue.get()
        print(result)

上面的代码应该打印输出类似于:

Start: Sat Jul  2 20:50:50 2016
End:   Sat Jul  2 20:50:55 2016
20
22

正如您所看到的,即使两个函数等待5秒钟以产生结果,它们也会并行执行,因此整体执行时间为5秒。

如果您关心什么函数将结果放入队列中,我可以看到两个解决方案,可以确定这一点。您可以创建多个队列或将结果包装在元组中。

def f1(q, x):
    time.sleep(5)
    # Tuple containing function information.
    q.put((f1, x * 2))

为了进一步简化(特别是当你有许多函数需要处理时),你可以修饰你的函数(避免重复代码并允许没有队列的函数调用):

def wrap_result(func):
    def wrapper(*args):
        # Assuming that shared queue is always the last argument.
        q = args[len(args) - 1]
        # We use it to store the results only if it was provided.
        if isinstance(q, Queue):
            function_result = func(*args[:-1])
            q.put((func, function_result))
        else:
            function_result = func(*args)
        return function_result

    return wrapper

@wrap_result
def f1(x):
    time.sleep(5)
    return x * 2

请注意,我的装饰器是匆忙编写的,其实现可能需要改进(例如,如果您的函数接受kwargs)。如果您决定使用它,则必须以相反的顺序传递您的参数:t1 = threading.Thread(target=f1, args=(x1, result_queue))

有点友好的建议。

“以下代码不起作用”对此问题一无所知。是否引发例外?是否会产生意想不到的结果?

阅读错误消息很重要。更重要的是 - 研究它们的意义。您提供的代码会引发TypeError非常明显的消息:

  

File ".../stack.py", line 16, in <module> out = (p.map([f1, f2], [x1, x2]))

     

TypeError: 'list' object is not callable

这意味着Pool().map()的第一个参数必须是callable对象,例如函数。让我们看看该方法的文档。

  

将func应用于iterable中的每个元素,并在a中收集结果   返回的列表。

显然不允许将函数列表作为参数传递。

Here您可以阅读有关Pool().map()方法的更多信息。

答案 1 :(得分:1)

  

我想同时执行f1和f2。但以下代码不起作用! ...

out=(p.map([f1, f2], [x1, x2]))

对代码的最小更改是将p.map()调用替换为:

r1 = p.apply_async(f1, [x1])
out2 = f2(x2)
out1 = r1.get()

虽然如果您想要同时运行两个函数调用,那么此处不需要Pool(),您可以手动启动一个线程/进程并use Pipe/Queue to get the result

#!/usr/bin/env python
from multiprocessing import Process, Pipe

def another_process(f, args, conn):
    conn.send(f(*args))
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe(duplex=False)
    p = Process(target=another_process, args=(f1, [x1], child_conn))
    p.start()
    out2 = f2(x2)
    out1 = parent_conn.recv()
    p.join()