跳转到主要内容
Chinese, Simplified

Python

  • Why Python Multiprocessing
  • 在 Python 中,单 CPU 使用是由全局解释器锁 (GIL) 引起的,它在任何给定时间只允许一个线程携带 Python 解释器。实现 GIL 是为了处理内存管理问题,但因此,Python 仅限于使用单个处理器。
  • 模块的多处理允许程序员充分利用给定机器上的多个处理器。使用的 API 类似于经典的线程模块。它提供本地和远程并发。
  • 多处理模块通过使用子进程而不是线程来避免全局解释器锁 (GIL) 的限制。多处理代码的执行顺序与串行代码不同。不能保证第一个创建的进程将是第一个完成的。

为什么多处理有用?


计算从 1 到 1000 的所有数字的最快方法是什么?

  • Python 一次只使用一个内核来工作。想想在解决一个简单的数学问题时做什么更快。
  • 通过将结果一一相加,并以递增方式将总和相加(1+2=3、3+3=6,6+4=1000,依此类推)。一个核心正在处理这项任务。
  • 预先将值拆分为单独的块,然后先将那里的值相加(1 到 300、301 到 600 和 601 到 1000)。三个核心将同时工作(最后一步是将收到的三个值相加)。

一个好的起点是了解 Python 中的多处理库是如何工作的。

你应该使用什么?

 

  • 如果你的代码有很多 I/O 或网络使用:多线程是你最好的选择,因为它的开销很低
  • 如果你有一个 GUI:多线程,这样你的 UI 线程就不会被锁定
  • 如果您的代码受 CPU 限制:您应该使用多处理(如果您的机器有多个内核)

多处理示例

 

  • Multiprocessing 是一个使用类似于 threading 模块的 API 支持生成进程的包。
  • multiprocessing 包提供本地和远程并发,通过使用子进程而不是线程来有效地避开全局解释器锁。
  • 因此,模块的多处理允许程序员充分利用给定机器上的多个处理器。 它可以在 Unix 和 Windows 上运行。
  • 这个使用 Pool 的数据并行的基本示例,
from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

将打印到标准输出:

[1, 4, 9]

进程类


在多处理中,进程是通过创建一个 Process 对象然后调用它的 start() 方法来产生的。 进程遵循threading.Thread的API。 多进程程序的一个简单示例是

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

为了显示所涉及的各个进程 ID,这是一个扩展示例:

 

from multiprocessing import Process
import os

def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())

def f(name):
    info('function f')
    print('hello', name)

if __name__ == '__main__':
    info('main line')
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

 

过程和例外:

  • run():方法代表进程的活动。
  • start():启动进程的活动。
  • join([timeout]):如果可选参数 timeout 为 None(默认值),则该方法将阻塞,直到调用该方法的 join() 的进程终止。
  • 名称:进程的名称。该名称是一个仅用于识别目的的字符串。
  • is_alive():返回进程是否存活。
  • terminate():终止进程
  • kill():与 terminate() 相同,但在 Unix 上使用 SIGKILL 信号。
  • close():关闭 Process 对象,释放与之相关的所有资源。
  • 异常 multiprocessing.ProcessError:所有多处理异常的基类。
  • 异常 multiprocessing.BufferTooShort:当提供的缓冲区对象太小而无法读取消息时,Connection.recv_bytes_into() 会引发异常。
  • 异常 multiprocessing.AuthenticationError:出现身份验证错误时引发
  • 异常 multiprocessing.TimeoutError:超时到期时由具有超时的方法引发

管道和队列


当使用多个进程时,通常使用消息传递来进行进程之间的通信,并避免使用任何同步原语,如锁。
对于传递消息,可以使用 Pipe()(用于两个进程之间的连接)或队列(允许多个生产者和消费者)。

 

结论

 

  • 如果没有多处理,Python 程序会因为 GIL(全局解释器锁)而无法最大化系统的规格。
  • 多处理允许您创建可以同时运行的程序(绕过 GIL)并使用整个 CPU 内核。 虽然它与线程库根本不同,但语法非常相似。 多处理库为每个进程提供了自己的 Python 解释器和自己的 GIL。
  • 因此,与线程相关的常见问题(例如数据损坏和死锁)不再是问题。 由于进程不共享内存,因此它们不能同时修改相同的内存。

谢谢阅读。 如果您觉得这篇文章有用,请不要忘记鼓掌并与您的朋友和同事分享。 如果您有任何问题,请随时与我联系。

原文:https://hiteshmishra708.medium.com/multiprocessing-in-python-c6735fa70f…

本文:https://jiagoushi.pro/node/1912

Article
知识星球
 
微信公众号
 
视频号