【Python使用】嘿马python高级进阶全体系教程第7篇:My Awesome Book,死锁【附代码文档】

举报
程序员一诺python 发表于 2025/09/01 20:51:53 2025/09/01
【摘要】 1.静态Web服务器涵盖固定页面数据返回、命令行启动动态端口绑定。2. Python高级特性包括闭包变量修改、装饰器(定义、语法糖、执行时间统计)、property属性、with语句和上下文管理器、深拷贝和浅拷贝。3. 正则表达式涉及多字符匹配(*、{m,n})、开头结尾匹配(^$)、字符排除匹配、分组匹配。4. 操作系统基础包括操作系统概念、虚拟机软件、Ubuntu系统、Li

🏆🏆🏆教程全知识点简介:1.静态Web服务器涵盖固定页面数据返回、命令行启动动态端口绑定。2. Python高级特性包括闭包变量修改、装饰器(定义、语法糖、执行时间统计)、property属性、with语句和上下文管理器、深拷贝和浅拷贝。3. 正则表达式涉及多字符匹配(*、{m,n})、开头结尾匹配(^$)、字符排除匹配、分组匹配。4. 操作系统基础包括操作系统概念、虚拟机软件、Ubuntu系统、Linux内核及发行版。5. Linux命令系统涵盖目录查看、路径操作、文件操作(ls、mkdir、rm、cp、mv)、重定向、文件内容查看、链接、压缩解压缩(tar、zip)。6. 系统管理包括文件权限(chmod)、用户权限(whoami、passwd)、用户创建、编辑器vim、软件安装卸载。7. 并发编程涵盖多任务概念、进程(进程编号获取、参数传递)、线程(执行特性、共享变量、死锁处理)、进程线程对比、协程(概念、优点、gevent)。8. 网络编程包括端口概念、TCP协议特点、socket使用、TCP开发流程、客户端服务端开发。9. HTTP协议涉及浏览器服务器通信、URL组成、开发者工具使用。


📚📚👉👉👉本站这篇博客:   https://bbs.huaweicloud.com/blogs/458180    中查看

📚📚👉👉👉本站这篇博客:   https://bbs.huaweicloud.com/blogs/453541    中查看

📚📚👉👉👉本站这篇博客:   https://bbs.huaweicloud.com/blogs/453541    中查看

✨ 本教程项目亮点

🧠 知识体系完整:覆盖从基础原理、核心方法到高阶应用的全流程内容
💻 全技术链覆盖:完整前后端技术栈,涵盖开发必备技能
🚀 从零到实战:适合 0 基础入门到提升,循序渐进掌握核心能力
📚 丰富文档与代码示例:涵盖多种场景,可运行、可复用
🛠 工作与学习双参考:不仅适合系统化学习,更可作为日常开发中的查阅手册
🧩 模块化知识结构:按知识点分章节,便于快速定位和复习
📈 长期可用的技术积累:不止一次学习,而是能伴随工作与项目长期参考


🎯🎯🎯全教程总章节


🚀🚀🚀本篇主要内容

This file file serves as your book's preface, a great place to describe your book's content and ideas.

死锁

学习目标

  • 能够知道产生死锁的原因

1. 死锁的概念

死锁: 一直等待对方释放锁的情景就是死锁

为了更好的理解死锁,来看一个现实生活的效果图:

图片无法加载

说明:

现实社会中,男女双方一直等待对方先道歉的这种行为就好比是死锁。

死锁的结果

  • 会造成应用程序的停止响应,不能再处理其它任务了。

2. 死锁示例

需求:

根据下标在列表中取值, 保证同一时刻只能有一个线程去取值

import threading
import time



# 创建互斥锁


lock = threading.Lock()




# 根据下标去取值, 保证同一时刻只能有一个线程去取值


def get_value(index):

    # 上锁
    lock.acquire()
    print(threading.current_thread())
    my_list = [3,6,8,1]
    # 判断下标释放越界
    if index >= len(my_list):
        print("下标越界:", index)
        return
    value = my_list[index]
    print(value)
    time.sleep(0.2)
    # 释放锁
    lock.release()


if __name__ == '__main__':
    # 模拟大量线程去执行取值操作
    for i in range(30):
        sub_thread = threading.Thread(target=get_value, args=(i,))
        sub_thread.start()

3. 避免死锁

  • 在合适的地方释放锁

[Kivy 文档]

import threading
import time



# 创建互斥锁


lock = threading.Lock()




# 根据下标去取值, 保证同一时刻只能有一个线程去取值


def get_value(index):

    # 上锁
    lock.acquire()
    print(threading.current_thread())
    my_list = [3,6,8,1]
    if index >= len(my_list):
        print("下标越界:", index)
        # 当下标越界需要释放锁,让后面的线程还可以取值
        lock.release()
        return
    value = my_list[index]
    print(value)
    time.sleep(0.2)
    # 释放锁
    lock.release()


if __name__ == '__main__':
    # 模拟大量线程去执行取值操作
    for i in range(30):
        sub_thread = threading.Thread(target=get_value, args=(i,))
        sub_thread.start()

4. 小结

  • 使用互斥锁的时候需要注意死锁的问题,要在合适的地方注意释放锁。
  • 死锁一旦产生就会造成应用程序的停止响应,应用程序无法再继续往下执行了。

进程和线程的对比

学习目标

  • 能够知道进程和线程的关系

1. 进程和线程的对比的三个方向

  1. 关系对比
  2. 区别对比
  3. 优缺点对比

2. 关系对比

  1. 线程是依附在进程里面的,没有进程就没有线程。
  2. 一个进程默认提供一条线程,进程可以创建多个线程。

2. 区别对比

  1. 进程之间不共享全局变量

  2. 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步

  3. 创建进程的资源开销要比创建线程的资源开销要大

  4. 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位

  5. 线程不能够独立执行,必须依存在进程中

  6. 多进程开发比单进程多线程开发稳定性要强

3. 优缺点对比

  • 进程优缺点:

  • 优点:可以用多核

  • 缺点:资源开销大

  • 线程优缺点:

  • 优点:资源开销小

  • 缺点:不能使用多核

4. 小结

  • 进程和线程都是完成多任务的一种方式
  • 多进程要比多线程消耗的资源多,但是多进程开发比单进程多线程开发稳定性要强,某个进程挂掉不会影响其它进程。
  • 多进程可以使用cpu的多核运行,多线程可以共享全局变量。
  • 线程不能单独执行必须依附在进程里面

协程

协程,又称微线程,纤程。英文名Coroutine。

协程是啥

协程是python个中另外一种实现多任务的方式。

只不过比线程更小占用更小执行单元(理解为需要的资源)。

通俗的理解:

在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。

协程的优点

最大的优势就是协程极高的执行效率。因为函数切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

gevent

gevent 是一个第三方库。

Python中仅提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

其原理是当一个任务函数遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的任务函数执行,等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有任务函数在运行,而不是等待IO,得以实现多任务,提高程序执行效率。

安装

pip3 install gevent

1. gevent的使用

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

运行结果

<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4

[TensorFlow 文档]

可以看到,3个greenlet是依次运行而不是交替运行

2. gevent切换执行

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        #用来模拟一个耗时操作,注意不是time模块中的sleep
        gevent.sleep(1)

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

运行结果

[Playwright Python]

<Greenlet at 0x7fa70ffa1c30: f(5)> 0
<Greenlet at 0x7fa70ffa1870: f(5)> 0
<Greenlet at 0x7fa70ffa1eb0: f(5)> 0
<Greenlet at 0x7fa70ffa1c30: f(5)> 1
<Greenlet at 0x7fa70ffa1870: f(5)> 1
<Greenlet at 0x7fa70ffa1eb0: f(5)> 1
<Greenlet at 0x7fa70ffa1c30: f(5)> 2
<Greenlet at 0x7fa70ffa1870: f(5)> 2
<Greenlet at 0x7fa70ffa1eb0: f(5)> 2
<Greenlet at 0x7fa70ffa1c30: f(5)> 3
<Greenlet at 0x7fa70ffa1870: f(5)> 3
<Greenlet at 0x7fa70ffa1eb0: f(5)> 3
<Greenlet at 0x7fa70ffa1c30: f(5)> 4
<Greenlet at 0x7fa70ffa1870: f(5)> 4
<Greenlet at 0x7fa70ffa1eb0: f(5)> 4

3. 给程序打补丁

from gevent import monkey
import gevent
import random
import time

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
        gevent.spawn(coroutine_work, "work1"),
        gevent.spawn(coroutine_work, "work2")
])

[python-docx 文档]

运行结果

work1 0
work1 1
work1 2
work1 3
work1 4
work1 5
work1 6
work1 7
work1 8
work1 9
work2 0
work2 1
work2 2
work2 3
work2 4
work2 5
work2 6
work2 7
work2 8
work2 9
from gevent import monkey
import gevent
import random
import time



# 有耗时操作时需要


monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
        gevent.spawn(coroutine_work, "work1"),
        gevent.spawn(coroutine_work, "work2")
])

运行结果

work1 0
work2 0
work1 1
work1 2
work1 3
work2 1
work1 4
work2 2
work1 5
work2 3
work1 6
work1 7
work1 8
work2 4
work2 5
work1 9
work2 6
work2 7
work2 8
work2 9

This file file serves as your book's preface, a great place to describe your book's content and ideas.

IP 地址的介绍

学习目标

  • 能够说出IP 地址的作用

1. IP 地址的概念

IP 地址就是标识网络中设备的一个地址,好比现实生活中的家庭地址。

网络中的设备效果图:

2. IP 地址的表现形式

说明:

  • IP 地址分为两类: IPv4IPv6

  • IPv4 是目前使用的ip地址

  • IPv6 是未来使用的ip地址

  • IPv4 是由点分十进制组成

  • IPv6 是由冒号十六进制组成

2. IP 地址的作用

IP 地址的作用是标识网络中唯一的一台设备的,也就是说通过IP地址能够找到网络中某台

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。