Python 踩坑记
前言
回归 Python 栈,相较 Go 的 Coding,Python 确实偏向复杂,看似编码方便快捷的背后,是越来越庞杂的细枝末节,稍不注意就是偏差。如果项目只是“能跑就行”,那大概率遍地是坑。开启踩坑记~
内存泄漏
服务内存缓慢持续上涨,内存泄漏,Python 相对还是好找一些,第一反应全局 Mutable 的变量再被持续 append? 寻迹之下发现不是,而是另外一种形式,危险的 Mutable 默认参数!
def some_decorator(default={}):@functools.wraps(func)def wrapper(*args, **kwargs):res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():default[k] = vrecord(default)return resreturn wrapper
本意是该装饰器在使用时会传入字典变量 default
用以后续记录内容中做一些基本信息植入。当不传时默认给一个空 dict
。
问题就出现在这。
参数默认值的设定,都是在定义时设置一次,也就是说 default={}
的默认参数,并不是在每次调用时候,去执行 new
一个新 dict
传入 default
,那么在大量都是缺省default 参数指定的默认值调用中,后续装饰器的内就会去不停写入 default
默认值的 dict
中的内容,如果外层 kwargs['target']
中的 kv 又是大面积不重复的 kv 对,因此这里就变成一个 内存泄漏点,并且实际行为也是不符合预期的。
优化上文,剔除可变参数:
def some_decorator(default=None):@functools.wraps(func)def wrapper(*args, **kwargs):local = default or {}res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():local[k] = vrecord(local)return resreturn wrapper
真的修复了么?当使用是,不传入行参给 default
本地 new
一个 dict
貌似可以了。
# 如果这样使用呢?
@some_decorator(default={'test_key': 'test_value'})
def some_fun(*args, **kwargs):pass
闭包陷阱
,装饰器声明时候调用一次,此时 loacl 被固定指向了 声明时传入的对象,后续所有的修改,都是在持续修改该对象,还是潜在泄漏
,修复如下:
def some_decorator():@functools.wraps(func)def wrapper(*args, **kwargs):local = kwargs.get('default', {})res = func(*args, **kwargs)if isinstance(kwargs['target'], dict):for k, v in kwargs['target'].items():local[k] = vrecord(local)return resreturn wrapper
pydantic
package 的安装使用不再赘述,参考 https://docs.pydantic.dev/latest/ 介绍,但是个别细节还是容易踩坑
首先是 从 BaseModel
集成来的子类定义式中的 变量命名
pydantic.BaseModel
的很大一个应用场景是 帮我们做一个 实例对象 属性类型的校验,下例会有什么效果?
import datetime
from pydantic import BaseModelclass Test(BaseModel):attr: dict_flag: strt = Test(attr={'time': datetime.datetime(2018, 1, 30, 13, 55, 28)}, _flag='hello'
)
print(t._flag)
print(t.json())
执行发
Traceback (most recent call last):File "/Users/machao/miniconda3/envs/py3.9/lib/python3.9/site-packages/pydantic/main.py", line 746, in __getattr__return self.__pydantic_private__[item] # type: ignore
KeyError: '_region'
_region
这种 ‘_’ 命名的私有变量不会再 实例对象中初始化,不妨 打印 t.__dict__
看下便知道
注释 print(t._flag)
程序顺利执行,这里 attr
中的 datetime
对象 顺利序列化了……
普通的 json.dumps()
都是要手动转一下 datetime
的,这里 json 顺利就完成了。
这种宽字典,其中 可选存在 datetime
字段时,如果想做中间缓存,手动 json.dumps()
存入 kv
又会遭中。
pydantic = 2.6.4
的较新版本中,对于转化就仅有的几句介绍:model_dump_json,能够对常规josn.dumps
中不兼容的 datetime
、date
或 UUID
做到兼容。
这里的内部实现没有明确说明,源码也没有,不过对于老一些的 pydantic = 2.6.4
他的兼容实现,就是类似调用 josn.dumps
的时候指定 default
,笔者在 旧版本上做过 debug
,内部就是指定了不同类型的 encoder
,可以参考 deprecated 中的 ENCODERS_BY_TYPE
线程
可能是 Go
的 Goroutine
用多了,Python
threading
很多细节被颠覆了,总觉得开了 threading
不 join
主程序执行完退出整个程序就退了,分别看下原始 threading
包和 concurrent
中的 ThreadPoolExecutor
threading
def rand_sleep(i):time.sleep(random.randint(2, 10))print(f'close thread: {i}')# 样例一
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,)) for i in range(5)]for t in threads:t.start()print('end main')
执行结果:
end main
close thread: 4
close thread: 3
close thread: 0
close thread: 1
close thread: 2Process finished with exit code 0
主程序执行完后会等待开的子线程执行完毕方才退出,顺序上,threads
开启后主程序继续往后执行,如果想要 threads
开启后阻塞住当前主进程,需调整如下
# 样例二
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,)) for i in range(5)]for t in threads:t.start()# t.join() 此处 join 变成串行了for t in threads:t.join()print('end main')
执行结果
close thread: 1
close thread: 2
close thread: 3
close thread: 4
close thread: 0
end mainProcess finished with exit code 0
Thread
初始化中有个默认参数 daemon
用来设置 守护线程,在默认情况下是,当前进程,如果
在样例一的编码中,维持其他不变,添加参数 daemon=True
# 样例三
if __name__ == '__main__':threads = [Thread(target=rand_sleep, args=(i,), daemon=True) for i in range(5)]for t in threads:t.start()print('end main')
此时主进程执行完即退出,不会等待子线程,除非类似 样例二中 手动 join
concurrent.futures
Python
3.2 引入的并发库,让我们的开启并行的形式更简明,
# 样例一
if __name__ == '__main__':tasks = []with ThreadPoolExecutor(max_workers=10) as executor:for i in range(5):tasks.append(executor.submit(rand_sleep, i))print('end main')
执行结果
close thread: 4
close thread: 1
close thread: 0
close thread: 2
close thread: 3
end mainProcess finished with exit code 0
没有手动去调用 join
啊,为什么会阻塞主线程了,ThreadPoolExecutor
的上下文协议管理做了什么?
# ThreadPoolExecutor 的父类
class Executor(object):....def __exit__(self, exc_type, exc_val, exc_tb):self.shutdown(wait=True)return Falseclass ThreadPoolExecutor(_base.Executor):......def shutdown(self, wait=True, *, cancel_futures=False):with self._shutdown_lock:self._shutdown = Trueif cancel_futures:# Drain all work items from the queue, and then cancel their# associated futures.while True:try:work_item = self._work_queue.get_nowait()except queue.Empty:breakif work_item is not None:work_item.future.cancel()# Send a wake-up to prevent threads calling# _work_queue.get(block=True) from permanently blocking.self._work_queue.put(None)if wait:for t in self._threads:t.join()
shutdown
的方法里,默认是开启 wait
会 join
住主线程
# 样例二
if __name__ == '__main__':tasks = []executor = ThreadPoolExecutor(max_workers=10)for i in range(5):tasks.append(executor.submit(rand_sleep, i))print('end main')
执行结果
end main
close thread: 1
close thread: 0
close thread: 2
close thread: 3
close thread: 4Process finished with exit code 0
类似 threading
没有 join
的效果,翻看源码会发现,submit
内部会开启 Thread
效果仿佛类似 threading
等待底层的线程调度器来做逻辑处理,其实还是不一样
在 concurrent.futures.thread
中,定义了
def _python_exit():global _shutdownwith _global_shutdown_lock:_shutdown = Trueitems = list(_threads_queues.items())for t, q in items:q.put(None)for t, q in items:t.join()# 注册到 threading 包的 _register_atexit 中
threading._register_atexit(_python_exit)# threading 中如下
def _register_atexit(func, *arg, **kwargs):"""CPython internal: register *func* to be called before joining threads.The registered *func* is called with its arguments just before allnon-daemon threads are joined in `_shutdown()`. It provides a similarpurpose to `atexit.register()`, but its functions are called prior tothreading shutdown instead of interpreter shutdown.For similarity to atexit, the registered functions are called in reverse."""if _SHUTTING_DOWN:raise RuntimeError("can't register atexit after shutdown")call = functools.partial(func, *arg, **kwargs)_threading_atexits.append(call)
体会下这里的区别吧,并且在 concurrent.futures
还提供了两个模块级的函数 concurrent.futures.wait
和 concurrent.futures.as_completed
可以在细读下 doc
先到这~ 未完待续~
相关文章:
Python 踩坑记
前言 回归 Python 栈,相较 Go 的 Coding,Python 确实偏向复杂,看似编码方便快捷的背后,是越来越庞杂的细枝末节,稍不注意就是偏差。如果项目只是“能跑就行”,那大概率遍地是坑。开启踩坑记~ …...

搭建Spark单机版环境
在搭建Spark单机版环境的实战中,首先确保已经安装并配置好了JDK。然后,从群共享下载Spark安装包,并将其上传至目标主机的/opt目录。接着,解压Spark安装包至/usr/local目录,并配置Spark的环境变量,以确保系统…...

使用Flutter混淆技术保护应用隐私与数据安全
在移动应用开发中,保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具,帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆,并提供了相关的操作步骤和注意事项。 📝 摘要 本…...

ClickHouse初体验
1.clickHouse是啥? ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS),使用 C语言编写,主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告 2.clickHouse的特点 2.1列式存储 对于列的聚合&…...
在k8s中部署高可用程序实践和资源治理
在k8s中部署高可用程序实践 1. 多副本部署1.1. 副本数量1.2. 更新策略1.3. 跨节点的统一副本分布1.4. 优先级1.5. 停止容器中的进程1.6. 预留资源 2. 探针2.1. 活性探针(liveness probes)2.2. 就绪探针(Readiness probe)2.3. 启动…...
WebView的使用与后退键处理-嵌入小程序或者 H5 页面
在使用 WebView 嵌入小程序或者 H5 页面时,通常会涉及到处理后退键的操作。在 Android 平台上,可以通过 WebView 的相关方法来实现后退键的处理。你可以按照以下步骤来实现: 在 Activity 或 Fragment 中找到 WebView 控件,并为其…...

【攻防世界】file_include (PHP伪协议+过滤器)
打开题目环境: 进行PHP代码审计,发现这是一个文件包含漏洞。 我们尝试利用PHP伪协议中的 php://filter来读取 check.php 中的内容。 构造payload 并提交: 发现payload被过滤掉了,我们就需要尝试使用不同的转换器。 PHP各类转换…...
Linux 内核中PHY子系统(网络):PHY驱动
一. 简介 PHY 子系统就是用于 PHY 设备相关内容的,分为 PHY 设备和 PHY 驱动,和 platform 总线一样,PHY 子系统也是一个设备、总线和驱动模型。 前面一篇文章学习了 PHY子系统中的 PHY设备。文章如下: Linux 内核中PHY子系统(网…...
【六 (1)机器学习-机器学习算法简介】
目录 文章导航一、机器学习二、基于学习方式的分类三、监督学习常见类型四、无监督学习常见类型五、强化学习常见分类 文章导航 【一 简明数据分析进阶路径介绍(文章导航)】 一、机器学习 机器学习是一门多领域交叉学科,涉及概率论、统计学…...
TCP服务端主动向客户端发送数据
C TCP 服务端和客户端通信的例子 在此基础上,要修改服务端代码,使其能够每秒向客户端发送当前时间,你需要添加一个循环,每次循环发送当前时间给客户端。同时,你需要在客户端代码中添加接收服务端发送的数据的逻辑。 …...

ObjectiveC-03-XCode的使用和基础数据类型
本节做为Objective-C的入门课程,笔者会从零基础开始介绍这种程序设计语言的各个方面。 术语 ObjeC:Objective-C的简称,因为完整的名称过长,后续会经缩写来代替;项目/工程:也称工程,指的是一个A…...

YOLOv9改进策略 :主干优化 | 无需TokenMixer也能达成SOTA性能的极简ViT架构 | CVPR2023 RIFormer
💡💡💡本文改进内容: token mixer被验证能够大幅度提升性能,但典型的token mixer为自注意力机制,推理耗时长,计算代价大,而RIFormers是无需TokenMixer也能达成SOTA性能的极简ViT架构 ,在保证性能的同时足够轻量化。 💡💡💡RIFormerBlock引入到YOLOv9,多个数…...

원클릭으로 주류 전자상거래 플랫폼 상품 상세 데이터 수집 및 접속 시연 예제 (한국어판)
클릭 한 번으로 전자상거래 플랫폼 데이터를 캡처하는 것은 일반적으로 웹 페이지에서 정보를 자동으로 추출 할 수있는 네트워크 파충류 기술과 관련됩니다.그러나 모든 형태의 데이터 수집은 해당 웹 사이트의 사용 약관 및 개인 정보 보호 정책 및 현지 법률 및 규정을 준수…...
2024年github开源top100中文
2024年github开源top100中文 动动美丽的小指头点个赞呗,感谢啦!💕💕💕😘😘😘 本文由Butterfly一键发布工具发布 语言star项目名称描述Python45670xai-org/grok-1Grok开源发布Ruby260…...

回收站删除的文件在哪里?专业恢复方法分享(最新版)
“我很想知道我从回收站删除的文件被保存在哪里了呢?我刚刚不小心清空了回收站,现在想将它们恢复,应该怎么操作呢?谁能教教我怎么从回收站恢复文件?” 回收站,作为Windows操作系统中的一个重要组件…...
什么是工时管理软件?
简而言之,工时管理软件是一种可以帮助管理者跟踪企业员工在项目和任务上花费的时间的软件。然而,工时管理软件不仅是一种收集信息的工具,它还是一种解决方案,使企业能够处理和优化不同的流程和活动,例如工资单、项目预…...

一文解析智慧城市,人工智能技术将成“智”理主要手段
长期以来,有关智慧城市的讨论主要围绕在技术进步方面,如自动化、人工智能、数据的公开以及将更多的传感器嵌入城市以使其更加智能化。实际上,智慧城市是一个关于未来的设想,其重要原因在于城市中存在各种基础设施、政治、地理、财…...

SQLBolt,一个练习SQL的宝藏网站
知乎上有人问学SQL有什么好的网站,这可太多了。 我之前学习SQL买了本SQL学习指南,把语法从头到尾看了个遍,但仅仅是心里有数的程度,后来进公司大量的写代码跑数,才算真真摸透了SQL,知道怎么调优才能最大化…...

TikTok防关联引流系统:全球多账号运营的终极解决方案
tiktok防关联引流系统介绍,tiktok防关联系统是基于tiktok生态研发的效率工具,帮你快速实现tiktok全球多账号运营,系统配备了性能强劲的安卓,防关联智能终端,可一建创建全球多国手机环境,完美满足各类app软件…...

卷积神经网络(CNN)的数学原理解析
文章目录 前言 1、介绍 2、数字图像的数据结构 3、卷积 4、Valid 和 Same 卷积 5、步幅卷积 6、过渡到三维 7、卷积层 8、连接剪枝和参数共享 9、卷积反向传播 10、池化层 11、池化层反向传播 前言 本篇主要分享卷积神经网络(CNN)的数学原理解析…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...