Python中非常简单的并发编程

时间:2012-05-07 00:29:04

标签: python concurrency

我有一个简单的Python脚本,它使用两个更复杂的Python脚本,并对结果做了一些事情。

我有两个模块,Foo和Bar,我的代码如下:

import Foo
import Bar

output = []

a = Foo.get_something()
b = Bar.get_something_else()

output.append(a)
output.append(b)

这两种方法都需要很长时间才能运行,而且两种方法都不依赖于其他方法,因此显而易见的解决方案是并行运行它们。我如何实现这一目标,但要确保维护订单:无论哪一个完成,必须等待另一个完成,然后脚本才能继续

请告诉我,如果我没有说清楚,我已尽力使示例代码尽可能简单。

修改

感谢Amber,您的解决方案稍作改动。

不是在创建每个线程时调用start(),而是将其设置为:

threadname = threading.Thread(target=foo)
threadname.start()

如果没有这个,我会收到错误AttributeError: 'NoneType' object has no attribute 'join'和一些非常的并发行为。如果您在下面编辑答案,我会将其标记为已解决。

2 个答案:

答案 0 :(得分:22)

通常,您可以使用threading来执行此操作。

首先,为要并行运行的每件事创建一个线程:

import threading

import Foo
import Bar

results = {}

def get_a():
    results['a'] = Foo.get_something()
a_thread = threading.Thread(target=get_a)
a_thread.start()

def get_b():
    results['b'] = Bar.get_something_else()
b_thread = threading.Thread(target=get_b)
b_thread.start()

然后要求两者都完成,请在两者上使用.join()

a_thread.join()
b_thread.join()

此时您的结果将显示在results['a']results['b']中,因此如果您想要一个有序列表:

output = [results['a'], results['b']]

注意:如果两个任务本身都是CPU密集型的,您可能需要考虑multiprocessing - 由于Python的GIL,给定的Python进程只会使用一个CPU核心,而multiprocessing可以将任务分配给单独的核心。但是,它的开销略高于threading,因此如果任务的CPU占用率较低,则可能效率不高。

答案 1 :(得分:8)

import multiprocessing

import Foo
import Bar

results = {}

def get_a():
    results['a'] = Foo.get_something()



def get_b():
    results['b'] = Bar.get_something_else()

process_a = multiprocessing.Process(target=get_a)
process_b = multiprocessing.Process(target=get_b)


process_b.start()
process_a.start()


process_a.join
process_b.join

以下是程序的流程版本。

注意:在线程中有共享数据结构,所以你必须担心锁定,这避免了错误的数据操作加上上面提到的琥珀色它还有一个GIL(全局解释器锁)问题,因为你的两个任务都是CPU密集型的那么这意味着由于调用通知线程获取和释放线程将花费更多时间。但是,如果您的任务是I / O密集型,那么它不会产生那么多影响。

现在由于流程中没有共享的数据结构,因此不用担心LOCKS,因为它与GIL无关,因此您实际上享受多处理器的真正功能。

要记住的简单注意事项:进程与不使用共享数据结构的线程相同(一切都是孤立的,并且专注于消息传递。)

查看dabeaz.com他曾就并发编程做过一次很好的演示。