ITPub博客

首页 > 数据库 > 数据库开发技术 > 不掌握这10个Python概念,请不要自称高级开发人员(二)~~

不掌握这10个Python概念,请不要自称高级开发人员(二)~~

原创 数据库开发技术 作者:jackzhang 时间:2024-12-02 06:30:00 0 删除 编辑

—— 路漫漫其修远兮,吾将上下而求索。

前路漫漫,我用Python探索世界。大家好,又到周末啦。今天我们继续分享成为高级开发人员必须要知道的10个 Python 概念的最后5个,大部分都提供了相应的学习资源,想要深入并掌握它们的伙伴可以直接使用。

6. 上下文管理器(Context Managers)

—— 先决条件:对资源管理的基本理解、try/except/finally 语句块

—— 相关概念:with 语句, __enter__ 和 __exit__ 魔术方法

如果你有一定编程经验的话,那么你应该知道我们需要多久与外部服务交互一次。无论是文件还是数据库,与任何外部服务交互的关键要点就是资源的合理分配与释放。

如果你是一个编程新手,那么你应该认得这种模式:

# 不使用上下文管理器的情况下打开文件并写入内容
file = open('test.txt', 'w')
try:
    file.write('Hello, world!')
finally:
    file.close()     # 关闭文件

这里,我们打开了一个文本文件,并与它交互,最重要的是交互完成后一定要记得关闭它,否则会造成资源浪费。

这是基本的资源分配和释放过程。当涉及到数据库连接时,你也会这样做。在工作完成后关闭连接。

上线文管理器(Context Managers)就是为了帮助我们简化这一过程。它是具有两个已实现的特殊方法(__enter__ 和 __exit__)的对象。当你进入上下文管理器时,使用 with 关键字,分配或__enter__ 部分被执行;而当你退出的时候,释放或 __exit__ 部分被执行。

因此,对于上面的文件交互示例,我们可以使用上下文管理器来简化它:

# 使用上下文管理器打开文件并写入内容
with open('test.txt', 'w') as f:
    f.write('Hello, world!')
# 在with语句块结束后,文件会自动关闭

—— 学习资源推荐:

  • https://www.datacamp.com/tutorial/writing-custom-context-managers-in-python
  • https://www.freecodecamp.org/news/context-managers-in-python/

7. 内存管理(Memory Management)

—— 先决条件:对变量和对象有基本的了解

—— 相关概念:垃圾回收、引用计数、sys.getrefcount()

Python 是一门高级编程语言,这意味着大多数复杂性对你来说都是经过抽象的,因此你只需要不按住应用程序的业务逻辑即可。

其中一个抽象概念就是内存管理(Memory Management)。Python 通过其垃圾回收机制负责复配和释放内存,因此你无需在每次使用后手动释放内存。

但是,你在编程过程中越高级,你想要控制的东西就会越多,这就是为什么了解 Python 中的内存管理概念如此重要的原因。它可以帮助你调试复杂问题,找到应用程序中的内存泄漏,以及更好的理解场景背后发生的实际情况。

对于内存管理,以下是你必须要了解的关键概念:

7.1 内存分配(Memory Allocation)

Python 通过私有堆管理内存,私有堆是专用于 Python 对象和数据结构的一块内存。Python 内存管理器负责分配和释放该内存。

  • 静态内存:这是为在运行时不会更改的变量分配的,通常存储在栈中。

  • 动态内存:这是为在运行时大小可能发生变化的对象分配的,通常存储在堆中。

7.2 内存池(Memory Pools)

Python 使用内存池系统实现对小型内存块的高效管理。创建对象时,Python 会检查池中是否有可容纳对象的可用块。如果没有,它会向操作系统请求额外的内存。这有助于减少与频繁分配和释放小内存块相关的开销。

7.3 引用计数嗯好垃圾回收(Reference Counting and Garbage Collection)

Python 采用两种主要技术来管理内存:

  • 引用计数:每个对象都会跟踪指向它的引用数量。当引用计数降至零时,就可以安全地销毁该对象(释放其占用的内存资源)。

  • 垃圾回收:为了处理循环引用(两个或多个对象相互引用),Python 使用垃圾回收器定期检查未引用的对象并释放它们所占用的内存。

7.4 代际垃圾回收(Generational Garbage Collection)

Python的垃圾回收器根据对象的生命周期将对象分为几代:

  • 年轻代:适用于新创建的对象。

  • 老年代:适用于在多个垃圾回收周期中幸存下来的对象。

这种分代方法通过专注于较年轻的对象来优化性能,这些对象更有可能很快变得无法访问。

—— 学习资源推荐:

  • https://realpython.com/python-memory-management/

8. 并发(Concurrency)

—— 先决条件:对程序执行流程有基本的了解

—— 相关概念:线程、多进程、异步编程

如果你负责的项目用户有多个,或者一次会运行多个任务,那么你就需要考虑使用并发。

按照传统定义,并发意味着可以同时运行多个任务。有多种方法可以做到这一点,有不同的并发类型,且它们之间有细微的差异,只有你深入挖掘它们的内部工作原理时,才会明白。

不同的并发类型:多线程、多进程和异步编程(asyncio)。

但你要记住一点,它们中只有一个(通常是多进程)真正在同时运行多个进程。

Python 中并发的关键主题:

8.1 线程(Threading)

threading 模块是Python运行并发任务最容易实现的方法之一。然而,由于全局解释器锁(Global Interpeter Lock, GIL),一次只有一个线程可以执行 Python 字节码,这就限制了真正的并行性。尽管如此,线程处理对于受 I/O 影响限制的任务(如文件处理或网络请求)可能照样很有效。这里的关键概念包括管理锁、理解 GIL 的影响,以及正确使用线程池(例如,concurrent.futures.ThreadPoolExecutor)。

8.2 多进程(Multiprocessing)

与线程不同,multiprocessing 模块允许 Python 程序通过创建单独的进程来绕过 GIL,每个进程都有自己的解释器和内存空间。这种方法实现真正的并行性,使其称为 GPU密集型任务的理想选择。但是,需要谨慎管理进程间通信和内存使用,通常需要更深入地了解共享内存、队列和用于管理工作进程池的 multiprocessing.Pool 类等主题知识。

8.3 异步编程(Asynchronous Programming)

随着 asyncio 和其他异步库(如 aiohttp 和 asyncpg)的引入,Python 现在对异步编程提供了强大的支持。这种方法对于 I/O 密集型和高延迟任务(如处理多个网络请求)特别强大。

了解 async/await 语法、事件循环和任务调度对掌握异步代码至关重要。这种模式与线程和多进程的区别在于,它依赖于非阻塞调用,允许多个任务在单个线程上看似并行运行。

8.4 并发库和框架(Libraries and Frameworks for Concurrency)

对于更高级的用法,Python 提供了简化并发管理的库,例如用于抽象线程和多进程的 concurrent.futures库和用于原生异步支持的 asyncio 库。像 gevent 和 Twisted 这样的工具提供了处理并发的替代方法,可能有助于高并发网络应用的探索。

Python 并发性的挑战:

Python 中的并发性带来了一些挑战,例如处理 GIL、管理资源竞争(例如死锁、竞争条件)和调试并发代码。此外,每个并发模式都引入了自己的权衡,要求开发人员根据工作负载(CPU 密集型还是 I/O 密集型)来选择正确的方法。

9. 全局解释器锁(Global Interpeter Lock, GIL)

—— 先决条件:了解并发以及 Python 内部的基础知识

—— 相关概念:线程安全操作、GIL 解决方案

GIL(即全局解释器锁)是标准 Python 解释器(CPython 版本)中的一种机制,它一次只允许一个线程执行 Python 字节码。这意味着即使在多线程 Python 程序中,在任何给定时刻都只有一个线程可以在解释器中执行。虽然 GIL 简化了内存管理并使 CPython 更加稳定,但它限制了 Python 在 CPU 密集型程序中执行真正并行性的能力。

既然如此,GIL 为什么还会存在呢?(很高兴你问了这个问题🤭)

我们都知道世间一切存在的事物都有其合理性(有点玄学的味道😄)。默认情况下, Python 的内存管理不是线程安全的,因此为了防止这种情况并有效地管理内存,在 CPython 版本中引入了 GIL。GIL 的实现使内存管理变得更加简单,因为它简化了引用计数,这是 Python 内存管理的核心。但这种方法也限制了 Python 在 CPU 密集型任务重执行真正并行性的能力。

为了防止篇幅过长,我们就不深入讨论这个主题了,下面我们一起探讨一下在该领域你应该注意哪些概念。

掌握 GIL 挑战应该探索的主题
  • 对于 I/O 密集型和 CPU 密集型任务,了解 GIL 是如何影响并发性的。
  • 线程限制:了解 GIL 如何影响 Python 的 threading 模块是决定何时使用线程还是进程的关键。
  • 多进程:熟练使用 multiprocessing 模块,因为它提供了不受 GIL 限制的基于进程的并行性。
  • 异步编程和非阻塞 I/O:对于 I/O 密集型任务,asyncio 模块提供了一种在没有线程的情况下实行并发的方法,从而绕过了与 GIL 相关的许多问题。
  • 替代 Python 实现:PyPy、Jython 和 IronPython 都是不是使用 GIL 或具有不同实现的替代解释器,对于特定用例来说可能会提供性能优势。

10. 协程和异步编程(Coroutines and Asynchronous Programming)

—— 先决条件:生成器、对并发有基本的了解

—— 相关概念:async/await 语法、事件循环、asyncio 模块

异步编程作为一种编程范式,可以达到对资源的高效利用。

想象一下,餐厅里有一个队列,每个人都点餐、付款和接收他的订单,然后才从队列中移动。这是同步执行的,其中一个任务会阻止其他任务的执行,即使它们只是在等待。

现在,在另一家餐厅,你在排队等候、点单并领取收据,然后移动到另一个队列等候,这意味着你不会阻止下一个排队的人。这就是从非常表面的层面上,我们想用异步编程解决的事。

你应该了解的异步编程主题(与语言无关的概念):

  • 理解阻塞和非阻塞任务之间的区别
  • 事件循环
  • 回调和承诺/未来:回调是指在某个操作完成后被调用的函数,常用于处理异步事件。而承诺和未来则是用于表示异步操作的结果,允许程序在等待操作完成的同时继续执行其他任务。
  • 协程
  • 异步上下文中的错误处理

在 Python 中,通过 asyncio 库支持异步编程。你可以使用关键字 async 定义一个函数,该关键字会将这个函数转换为协程,这样的话,该函数就可以在异步上下文中执行。

要执行一个 async 函数(协程),通常要在另一个函数中使用 await,也可以在事件循环中运行它(例如,使用 asyncio.run())。

最后的话

好啦,干活有点多,但是只要你花时间搞懂并实践它们,相信你的编程水平一定会得到显著提升,迈入高级开发人员行列。作为 Python 开发人员,正确理解并应用这些概念将为你在工作中带来巨大优势。

希望你能从这篇文章中有所收获,感谢你的阅读!如果觉得不错的话可以给辛苦码子的笔者加个鸡腿(🍗💴)🙇‍🙂


推荐阅读👇👇👇

不掌握这10个Python概念,请不要自称高级开发人员(一)~~

Python必知必会:使用 dedent() 方法优雅地展示多行字符串!

Python必知必会:39个Python关键字详解,你的编程查阅小手册,收藏!

Python必知必会:每个程序员都必须知道的22个Python单行代码!

Python必知必会:15个令人相见恨晚的Python字符串格式化技巧!

- END -

🌟 如果你喜欢这篇文章并且愿意支持我的话,你可以:🌟

  • 👍👍👍 点赞文章
  • ⤴️⤴️⤴️ 转发文章
  • ⚛️⚛️⚛️ 点击在看
  • 🧑‍🤝‍🧑🧑‍🤝‍🧑🧑‍🤝‍🧑 让文章被推荐给更多人,找到更多志同道合的伙伴
  • 👏👏👏 欢迎给我留言

关注我,第一时间接收更多关于Python、数据分析和机器学习的深入分析和最新趋势。我们一起探索数据的力量,解锁AI的潜能。你的每一次互动都是对我的极大鼓励,也是我们共同成长的动力!

👇👇👇 关注并开启星标提醒,让知识与技能的火花不断在你的职业道路上燃烧吧!

原文作者:数据派探险家;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2017-12-19

  • 博文量
    119
  • 访问量
    55949