【问题标题】:Very simple concurrent programming in PythonPython中非常简单的并发编程
【发布时间】:2012-05-07 00:29:04
【问题描述】:

我有一个简单的 Python 脚本,它使用两个更复杂的 Python 脚本,并对结果进行处理。

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

import Foo
import Bar

output = []

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

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

这两种方法都需要很长时间才能运行,而且都不依赖于另一个,因此显而易见的解决方案是并行运行它们。我怎样才能做到这一点,但要确保保持顺序:先完成的必须等待另一个完成,然后脚本才能继续

如果我说得不够清楚,请告诉我,我已尝试使示例代码尽可能简单。

【问题讨论】:

    标签: python concurrency


    【解决方案1】:

    一般来说,您会使用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 密集度较低,它可能不会那么高效。

    【讨论】:

    • 线程对于空闲的代码很有帮助。如果它有很多繁重的计算,你应该建议多处理,因为在这种情况下线程只会增加滞后。
    • 是的,它非常占用 CPU。不过,我会先让这个工作;我快速浏览了一下,API 是相同的。
    • 我已经尝试了一段时间,但我不断收到错误:AttributeError: 'NoneType' object has no attribute 'join' 每次都指的是 a_thread。 b_thread 按预期工作。
    • @Blazemore 我稍微编辑了代码,有一点小问题。
    • 您知道为什么我在访问结果字典时可能会遇到问题吗?我得到关键错误。让函数写入任何全局变量也给我带来了问题;它只是不写它们。
    【解决方案2】:
    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,他曾经就并发编程做了很好的介绍。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      相关资源
      最近更新 更多