【问题标题】:how are the multiprocessing and threading and thread pooling working多处理和线程和线程池如何工作
【发布时间】:2017-05-05 04:02:33
【问题描述】:

https://code.tutsplus.com/articles/introduction-to-parallel-and-concurrent-programming-in-python--cms-28612 从我研究过的这个链接,我有几个问题 Q1:线程池(并发)和线程在这里有何不同?为什么我们看到性能改进。线程与 Que 有 4 个线程,每个线程在空闲时间协同运行,并在获得网站响应后从 Que 中选择项目。如我所见,线程池也在某种程度上做同样的事情。完成工作并等待经理分配任务;这与从 Que 中挑选新物品非常相似。我不确定这有什么不同以及为什么我看到性能改进。似乎我在这里解释极化是错误的。你能解释一下吗

Q2:问题 2:使用多处理所花费的时间更多。如果我有一个可以一次处理多个进程的多处理器,那么我的所有 4 个进程都应该由它一次处理。那是真正的并行化正在发生。另外,我在这里有一个问题——在这种情况下,由于 4 个进程正在运行相同的函数,GIL 不会尝试阻止它们执行相同的代码。让我们假设它们都共享一个更新的公共变量——比如检查的网站数量。那么 GIL 在这些多处理的情况下是如何工作的呢? 此外,这里是一次又一次地使用相同的进程,或者它们在每次工作后都会被杀死和创建——我认为使用的是相同的进程。此外,我认为性能问题是因为与并发线程阶段的轻量级线程相比,进程创建是昂贵的。那么您能否更详细地解释 GIL 是如何在这里工作以及进程如何运行的,它们是否协同运行(就像每个进程等待轮到它一样 - 就像进程中的线程一样)。或者这些进程是否使用多处理器真正并行运行。另外,我的另一个问题是如果我有一台 8 核机器,我想我可以同时或并行运行同一进程的 8 个线程。如果我有 8 核机器,我可以运行 2 个进程,每个进程有 4 个线程吗?我可以在 8 个内核上运行 8 个进程吗?我认为核心仅用于进程的线程,这意味着我不能在 8 个核心上运行 8 个进程,但我可以运行与我的 CPU 或多处理器系统一样多的进程,对吗?那么我可以运行 2 个进程,每个进程有 4 个线程吗?在我的 8 核机器上,有 2 个多处理器,每个处理器有 4 个内核?

【问题讨论】:

  • 哈哈,子问题太多了,m8!我最终会回答的! :P

标签: multithreading parallel-processing multiprocessing ipython-parallel


【解决方案1】:

Python 有一组丰富的库,用于处理进程和线程的多任务。但是,库之间存在重叠,选择取决于您对计算任务的抽象程度。例如,concurrent.futures 库将线程视为异步任务,而Threading 库将它们视为高级线程。此外,_thread 实现了一个低级接口,用于公开所有同步机制的线程。

GIL(全局解释器锁)只是一个同步原语,特别是 mutex,它可以防止 同一进程的多个线程执行 Python 字节码片段(对于某些需要与并发操作保持一致的对象)。这正是 Python 线程在 I/O 操作方面优于计算密集型任务的原因。(因为 GIL 在某些阻塞调用/计算密集型库如numpy 的情况下被释放)。请注意,只有 CPythonPypy 版本的 Python 受 GIL 机制的约束。

现在,让我们看看这些问题...

  1. 线程池(并发)和线程在这里有何不同?为什么我们会看到性能提升?

比较 Threadingconcurrent.futures.ThreadPoolExecutor(又名 threading_squirrel 与 future_squirrel),我使用相同的测试用例执行了这两个程序。有两个因素促成了这种“性能提升”:

  • 网络 HEAD 请求:请记住,网络操作不必在每次执行它们时都在同一时间段内完成...由于数据包传输延迟的本质...

  • 线程执行顺序:在您链接的网站中,作者最初创建所有线程,设置充满网站链接的队列,然后在列表理解循环中启动所有线程。在ThreadPoolExecutorconcurrent.futures 中,每次提交任务时,如果未达到预定义的最大线程/worker 数,则会为其分配一个线程。我已经更改了代码以反映这种技术。 这似乎可以加快速度,因为第一个线程很早就开始工作并且不需要等待队列被填满......

  1. GIL 在这些多处理情况下如何工作?

请记住,GIL 仅对进程的线程生效,而不是在进程之间生效。 GIL 在执行线程期间锁定整个解释器字节码,因此其他线程必须等待轮到它们。这就是multiprocessing 使用进程而不是线程的原因,因为每个进程都有自己的解释器,因此,它有自己的 GIL。

  1. 相同的进程是一次又一次地使用,还是每次在工作结束后都会被杀死和创建?

池的概念是减少计算过程中创建和销毁工作人员(无论是线程还是进程)的开销。但是,从某种意义上说,这些进程有点“全新”,因为库有效地要求操作系统在基于 UNIX 的操作系统中执行 fork 或在基于 NT 的操作系统中执行 spawn...

  1. 另外,这些进程是否协同运行?

也许吧。如果他们使用共享内存,他们必须合作运行......(不需要一起运行)。如果进程的数量超过操作系统可以分配给其处理器内核的数量,那么肯定会发生上下文切换。如果没有共享内存更新,它们可以并行运行。

  1. 如果我有 8 核机器,我可以运行 2 个进程,每个进程有 4 个线程吗?我可以在 8 个内核上运行 8 个进程吗?

当然(受 GIL 约束,在 Python 中)。每个进程可以分配给每个处理单元执行。处理单元可以是 CPU 的物理或虚拟内核。只要操作系统调度程序支持它,它就是可能的。进程和线程的任何合理拆分都是可能的。如果所有都是可分配的,那是最好的情况,否则你会遇到上下文切换......(在进程方面更昂贵)

希望我已经回答了所有这些问题!

这里有一些资源:

MultiCore CPUs, Multithreading and context switching?

Why does multiprocessing use only a single core after I import numpy?

Bonus celery-squirrel resource

【讨论】:

    猜你喜欢
    • 2011-11-03
    • 1970-01-01
    • 2018-07-19
    • 2012-03-17
    • 2021-08-28
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    相关资源
    最近更新 更多