简体   繁体   English

在python中同时并行化不同的功能

[英]Parallelizing different functions at the same time in python

I want to execute f1 and f2 at the same time. 我想同时执行f1和f2。 but the following code doesn't work! 但是以下代码不起作用!

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]

I believe you'd like to use threading.Thread and shared queue in your code. 我相信您想在代码中使用threading.Thread共享队列

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)

Code above should print output similar to: 上面的代码应输出类似于以下内容的输出:

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

As you can see, even though both functions wait 5 seconds to yield their results, they do it in parallel so overall execution time is 5 seconds. 如您所见,即使两个函数都等待5秒钟才能产生结果,但它们都是并行执行的,因此总执行时间为5秒钟。

If you care about what function put what result in your queue, I can see two solutions that will allow to determine that. 如果您在乎什么函数将什么结果放入队列,我可以看到两种解决方案可以确定这一点。 You can either create multiple queues or wrap your results in a tuple. 您可以创建多个队列,也可以将结果包装在一个元组中。

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

And for further simplification (especially when you have many functions to deal with) you can decorate your functions (to avoid repeated code and to allow function calls without queue): 为了进一步简化(尤其是当您要处理许多函数时),您可以修饰函数(避免重复代码并允许函数调用而无需排队):

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

Note that my decorator was written in a rush and its implementation might need improvements (in case your functions accept kwargs, for instance). 请注意,我的装饰器是匆忙编写的,其实现可能需要改进(例如,如果您的函数接受kwargs)。 If you decide to use it, you'll have to pass your arguments in reverse order: t1 = threading.Thread(target=f1, args=(x1, result_queue)) . 如果决定使用它,则必须以相反的顺序传递参数: t1 = threading.Thread(target=f1, args=(x1, result_queue))

A little friendly advice. 一个友好的建议。

"Following code doesn't work" says nothing about the problem. “遵循以下代码无效”,对此问题一言不发。 Is it raising an exception? 是否引发例外? Is it giving unexpected results? 它会产生意想不到的结果吗?

It's important to read error messages. 阅读错误消息很重要。 Even more important - to study their meaning. 更重要的是-研究其含义。 Code that you have provided raises a TypeError with pretty obvious message: 您提供的代码会引发TypeError并带有明显的消息:

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

TypeError: 'list' object is not callable

That means first argument of Pool().map() have to be a callable object, a function for instance. 这意味着Pool().map()第一个参数必须是一个callable对象,例如一个函数。 Let's see the docs of that method. 让我们看看该方法的文档。

Apply func to each element in iterable, collecting the results in a list that is returned. 将func应用于可迭代的每个元素,将结果收集在返回的列表中。

It clearly doesn't allow a list of functions to be passed as it's argument. 显然,它不允许将函数列表作为参数传递。

Here you can read more about Pool().map() method. 在这里,您可以阅读有关Pool().map()方法的更多信息。

I want to execute f1 and f2 at the same time. 我想同时执行f1和f2。 but the following code doesn't work! 但是以下代码不起作用! ... ...

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

The minimal change to your code is to replace the p.map() call with: 对代码的最小更改是将p.map()调用替换为:

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

Though if all you want is to run two function calls concurrently then you don't need the Pool() here, you could just start a Thread/Process manually and use Pipe/Queue to get the result : 尽管如果您只想同时运行两个函数调用,那么这里不需要Pool() ,您可以手动启动线程/进程并使用Pipe / Queue来获得结果

#!/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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM