热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python并发编程_用Python进行并发编程不是您想的那样。

python并发编程最初发布于melvinkoh.me在本文中,我将首先带您了解并发编程与并行执行之间的区别,讨论有关Python内置的并发编程机制以及

python 并发编程

最初发布于 melvinkoh.me

在本文中,我将首先带您了解并发编程与并行执行之间的区别,讨论有关Python内置的并发编程机制以及Python中多线程的陷阱。

了解并发编程与并行执行

尽管事实上这两个术语经常互换使用,但并发编程并不等同于并行执行。

>没有并行的并发插图

并发是一个属性,可以同时运行多个操作,但这并不意味着可以并发。 (想象一下,如果您的处理器是单线程的。)

>并行性插图

并行是实际上同时运行操作的属性。 通常由硬件限制决定。

将您的程序视为一条快餐链,当构建两个单独的订单和收款柜台时,并发即被合并。 但是,它不能确保并行性,因为它取决于可用雇员的数量。 如果只有一名员工同时处理订单和收款请求,则这些操作不能并行运行。 仅当有两个员工同时服务于订单和收货时,才出现并行。

Python内置

现在,我们在Python中拥有什么? Python是否有内置程序可以帮助我们构建并发程序并使它们并行运行?

在下面的讨论中,我们假定我们的程序都是在多线程或多核处理器中编写并运行的。

答案是Jein (德语为是和否)。 为什么是? Python确实具有用于最常见的并发编程结构(多处理和多线程)的内置库。 您可能会认为,由于Python同时支持,为什么选择Jein? 原因是,由于Python中的GIL,Python中的多线程并不是真正的多线程。

多线程—基于线程的并行性

threading是提供用于创建和管理线程的API的软件包。 Python中的线程始终是不确定性的,它们的调度由操作系统执行。 但是,多线程可能无法达到您的预期。

为什么Python中的多线程可能不是您想要的?

除了常见的陷阱(如死锁)之外,多线程通常会出现饥饿。 Python因其在多线程中的性能较差而臭名昭著。

让我们看一下以下代码片段:

import threadingdef countdown () :x = 1000000000while x > 0 :x -= 1
# Implementation 1: Multi-threading
def implementation_1 () :thread_1 = threading.Thread(target=countdown)thread_2 = threading.Thread(target=countdown)thread_1.start()thread_2.start()thread_1.join()thread_2.join()
# Implementation 2: Run in serial
def implementation_2 () :countdown()countdown()

哪个实施会更快? 让我们执行一个定时。

>两种实现的时序结果

令人惊讶的是,连续运行2个countdown()胜过多线程吗? 这怎么可能呢? 多亏了臭名昭著的Global Interpreter Lock(GIL)。

什么是全局翻译锁定(GIL)?

在大多数情况下,取决于Python的分布是CPython的实现。 CPython是Python的原始实现,您可以在此StackOverflow线程中阅读有关它的更多信息。

在CPython中,通过引入称为全局解释器锁(又称为GIL)的互斥对象来支持多线程。 这是为了防止多个线程同时访问同一Python对象。 这是有道理的,您不希望其他人在处理对象时对其进行变异。

>实施示意图_1

因此,从上面的代码段中, implementation_1创建2个线程,并应在多线程系统上并行运行。 但是,一次只能有一个线程可以容纳GIL,一个线程必须等待另一线程释放GIL才能运行。 同时,由操作系统完成的调度和切换会带来开销,从而使implementation_1变得更加缓慢。

如何绕过GIL?

我们如何在保持多线程使用的同时绕过GIL? 这个问题没有通用的好答案,因为这与您的代码目的有所不同。

可以选择使用Jython,PyPy或IronPython等不同的Python实现。 我个人不主张使用不同的Python实现,因为大多数编写的库都没有针对不同的Python实现进行测试。

另一个可能的解决方法是使用C扩展,或更好地称为Cython 。 请注意,Cython和CPython是不同的。 您可以在此处阅读有关Cython的更多信息。

请改用多处理。 由于在多处理中,将为每个子进程创建一个解释器。 不存在争用GIL简单线程的情况,因为在每个进程中始终只有一个主线程。

尽管存在所有陷阱,我们是否仍应使用多线程?

如果您的任务是受I / O约束的,则意味着线程将花费大部分时间来处理I / O,例如执行网络请求。 仍然可以使用多线程,因为在大多数情况下,线程被操作系统阻塞并放入阻塞队列中。 线程也总是比进程少耗费资源。

多处理—基于过程的并行性

让我们使用多重处理实现我们之前的代码片段。

import multiprocessing
# countdown() is defined in the previous snippet.
def implementation_3 () :process_1 = multiprocessing.Process(target=countdown)process_2 = multiprocessing.Process(target=countdown)process_1.start()process_2.start()process_1.join()process_2.join()

结果本身是不言自明的。

>多处理与多线程的计时结果

结论

GIL的约束在最初作为Python开发人员时吸引了我。 直到我确定时机,我才意识到使用线程的决定是毫无价值的。 希望本文对您有所帮助。

翻译自: https://hackernoon.com/concurrent-programming-in-python-is-not-what-you-think-it-is-b6439c3f3e6a

python 并发编程



推荐阅读
author-avatar
永城之家_319
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有