线程和多处理模块之间有什么区别? - python

我正在学习如何在Python中使用threadingmultiprocessing模块来并行运行某些操作并加速我的代码。

我发现很难理解(也许是因为我没有任何理论背景)要理解threading.Thread()对象和multiprocessing.Process()对象之间的区别。

另外,对我来说,如何实例化一个作业队列并使其只有4个(例如)并行运行,而另一个则等待资源释放后再执行,对我来说也不是很清楚。

我发现文档中的示例很清楚,但并不十分详尽。一旦尝试使事情复杂化,就会收到很多奇怪的错误(例如无法腌制的方法,等等)。

那么,什么时候应该使用threadingmultiprocessing模块?

您能否将我链接到一些资源,这些资源解释这两个模块的概念以及如何在复杂的任务中正确使用它们?

参考方案

通常,What Giulio Franco says对于多线程与多处理是正确的。

但是,Python *还有一个问题:有一个全局解释器锁,可以防止同一进程中的两个线程同时运行Python代码。这意味着,如果您有8个核心,并且将代码更改为使用8个线程,则它将无法使用800%的CPU并无法以8倍的速度运行;它会使用相同的100%CPU,并以相同的速度运行。 (实际上,它的运行速度会稍慢一些,因为即使您没有任何共享数据,线程处理也会带来额外的开销,但是现在暂时忽略它。)

也有例外。如果您的代码繁重的计算实际上不是在Python中发生的,而是在某些具有自定义C代码的库中执行的,这些代码可以正确地进行GIL处理,例如numpy应用程序,那么线程将为您带来预期的性能收益。如果繁重的计算是由您运行并等待的某个子进程完成的,则情况也是如此。

更重要的是,在某些情况下,这无关紧要。例如,网络服务器花费大部分时间从网络上读取数据包,而GUI应用花费大部分时间来等待用户事件。在网络服务器或GUI应用程序中使用线程的原因之一是允许您执行长时间运行的“后台任务”,而又不会阻止主线程继续为网络数据包或GUI事件提供服务。这在Python线程中工作得很好。 (从技术上讲,这意味着Python线程为您提供了并发性,即使它们没有为您提供核心并行性。)

但是,如果您使用纯Python编写受CPU约束的程序,则使用更多线程通常无济于事。

对于GIL,使用单独的进程没有这种问题,因为每个进程都有自己的单独的GIL。当然,与其他语言相比,线程和进程之间仍然具有所有相同的权衡关系–在进程之间共享数据比在线程之间共享更加困难,而且成本更高,运行大量进程或创建和销毁这些开销可能会很高等等。但是GIL在处理方面的平衡上占了很大比重,对于C或Java而言,这是不正确的。因此,与使用C或Java相比,您会发现在Python中使用多处理的频率更高。

同时,Python的“含电池”理念带来了一些好消息:编写代码很容易,只需进行一次更改即可在线程和进程之间来回切换。

如果您根据独立的“作业”来设计代码,除了输入和输出之外,这些作业不与其他作业(或主程序)共享任何内容,则可以使用concurrent.futures库在线程池周围编写代码像这样:

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    executor.submit(job, argument)
    executor.map(some_function, collection_of_independent_things)
    # ...

您甚至可以获取这些作业的结果,并将其传递给其他作业,按执行顺序或完成顺序等待;等等。阅读有关Future对象的部分以获取详细信息。

现在,如果事实证明您的程序一直在使用100%CPU,并且添加更多线程只会使其速度变慢,那么您就遇到了GIL问题,因此您需要切换到进程。您要做的就是更改第一行:

with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:

唯一真正的警告是,作业的自变量和返回值必须可腌制(而不需要花费太多时间或内存来腌制)才能使用跨进程。通常这不是问题,但有时是问题。

但是,如果您的工作不能自给自足怎么办?如果您可以根据将消息从一个传递到另一个的工作来设计代码,那仍然很容易。您可能必须使用threading.Threadmultiprocessing.Process而不是依赖于池。并且您将必须显式创建queue.Queuemultiprocessing.Queue对象。 (还有很多其他选择,例如管道,套接字,带有斑点的文件等等。但是,要点是,如果执行器的自动魔力不足,则必须手动执行某些操作。)

但是,如果您甚至不能依靠消息传递怎么办?如果您需要两个工作来同时改变同一个结构并看到彼此的更改,该怎么办?在这种情况下,您将需要进行手动同步(锁定,信号量,条件等),并且,如果要使用进程,则需要显式的共享内存对象来引导。这是当多线程(或多处理)变得困难时。如果可以避免,那就太好了;如果不能,您将需要阅读的内容超过某人可以提供的答案。

通过评论,您想了解Python中的线程和进程之间的区别。确实,如果您阅读了朱利奥·佛朗哥的答案和我的知识以及我们所有的链接,那应该涵盖了所有内容...但是总结肯定会有用,所以这里是:

线程默认共享数据;流程没有。
(1)的结果是,在进程之间发送数据通常需要对其进行酸洗和取消酸洗。**
(1)的另一个结果是,在进程之间直接共享数据通常需要将其放入低级格式,例如Value,Array和ctypes类型。
流程不受GIL约束。
在某些平台(主要是Windows)上,创建和销毁进程的成本要高得多。
对流程有一些额外的限制,其中某些限制在不同平台上有所不同。有关详细信息,请参见Programming guidelines。
threading模块没有multiprocessing模块的某些功能。 (您可以使用multiprocessing.dummy在线程之上获取大多数缺少的API,或者可以使用诸如concurrent.futures之类的更高级别的模块,而不必担心。)

*出现此问题的实际上不是Python,而是该语言的“标准”实现CPython。其他一些实现没有JIL,例如Jython。

**如果您正在使用fork启动方法进行多处理(在大多数非Windows平台上可以使用),则每个子进程都将获得启动子级时父级拥有的任何资源,这可以是将数据传递到的另一种方式孩子们。

Python GPU资源利用 - python

我有一个Python脚本在某些深度学习模型上运行推理。有什么办法可以找出GPU资源的利用率水平?例如,使用着色器,float16乘法器等。我似乎在网上找不到太多有关这些GPU资源的文档。谢谢! 参考方案 您可以尝试在像Renderdoc这样的GPU分析器中运行pyxthon应用程序。它将分析您的跑步情况。您将能够获得有关已使用资源,已用缓冲区,不同渲染状态上…

Python sqlite3数据库已锁定 - python

我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…

python:ConfigParser对象,然后再阅读一次 - python

场景:我有一个配置文件,其中包含要执行的自动化测试的列表。这些测试是长期循环执行的。   配置文件的设计方式使ConfigParser可以读取它。由于有两个三个参数,因此我需要通过每个测试。现在,此配置文件由script(s1)调用,并且按照配置文件中的列表执行测试。Script(s1)第一次读取配置,并且在每次测试完成后都会执行。阅读两次的要求:由于可能会…

Python exchangelib在子文件夹中读取邮件 - python

我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…

python-docx应该在空单元格已满时返回空单元格 - python

我试图遍历文档中的所有表并从中提取文本。作为中间步骤,我只是尝试将文本打印到控制台。我在类似的帖子中已经看过scanny提供的其他代码,但是由于某种原因,它并没有提供我正在解析的文档的预期输出可以在https://www.ontario.ca/laws/regulation/140300中找到该文档from docx import Document from…