None: self.prompt += other.prompt self.completion += other.completion self.total += other.total ">

当前位置:

首页 > 编程开发 > python中add()和__add__()的用法小结

python中add()和__add__()的用法小结

先看区别: 方案 1:add()原地修改 def add(self, other: "Usage") -> None: self.prompt += other.prompt self.completion += other.completion self.total += other.total

先看区别:

方案 1:add()原地修改

def add(self, other: "Usage") -> None:
    self.prompt += other.prompt
    self.completion += other.completion
    self.total += other.total
    self.cached += other.cached
    self.calls += other.calls
    self.cost += other.cost

使用:

python中add()和__add__()的用法小结

total = Usage()
total.add(usage1)
total.add(usage2)

✅ 优点:性能更好

不会创建新对象,适合大量累加:

usage = Usage()

for item in usages:
    usage.add(item)

避免大量临时 Usage() 对象。

❌ 缺点:会改变自身

例如:

a = Usage(prompt=100)
b = a

a.add(Usage(prompt=50))

print(b.prompt)

结果:

150

因为 a 和 b 指向同一个对象。

这可能导致隐藏 bug。

方案 2:__add__()返回新对象

def __add__(self, other: "Usage") -> "Usage":
    return Usage(
        prompt=self.prompt + other.prompt,
        completion=self.completion + other.completion,
        total=self.total + other.total,
        cached=self.cached + other.cached,
        calls=self.calls + other.calls,
        cost=self.cost + other.cost,
    )

使用:

total = usage1 + usage2

✅ 优点:更安全

例如:

total = usage1 + usage2

print(usage1)

usage1 不会改变。

这符合函数式思想:

输入不变,输出新值

支持链式计算

total = u1 + u2 + u3 + u4

❌ 缺点:创建很多对象

result = Usage()

for u in usages:
    result = result + u

实际上:

第1次:

Usage对象A + u1 -> B

第2次:

B + u2 -> C

第3次:

C + u3 -> D

现在我们看原地更改的问题: 可以直接看3.

1. 引用共享导致意外修改(复制引用)

例如:

usage = Usage(prompt=100)

backup = usage

usage.add(Usage(prompt=50))

print(backup.prompt)

结果:

150

很多人会以为:

backup = usage

是复制,但 Python 只是复制引用。

图示:

backup ─┐
        ├──> Usage(prompt=100)
usage ──┘

add() 修改的是这个对象本身。

2. 作为函数参数传递时 (更改全局状态)

例如:

def calculate_total(usage):
    usage.add(Usage(prompt=100))
    return usage

u = Usage(prompt=10)

result = calculate_total(u)

print(u.prompt)

输出:

110

3. 多线程环境下可能出现数据竞争

例如你的场景:

  • 多个 LLM 请求同时完成
  • 都更新一个全局 Usage

类似:

global_usage.add(response_usage)

线程 A:

读取 prompt=100

+50

写回150

线程 B:

读取 prompt=100

+30

写回130

最终:

130

而不是:

180

为:

self.prompt += other.prompt

不是原子操作。

实际上等价:

tmp = self.prompt
tmp = tmp + other.prompt
self.prompt = tmp

多线程会丢更新。

解决: 加锁

from threading import Lock

lock = Lock()

with lock:
    usage.add(other)

我的选择:add()保持现有框架

是的,add() 本身不是线程安全的.

不过重点是:当前这份代码里,add() 暂时没有并发问题。

每个线程里,各自跑自己的 Workflow

原因是现在的并发结构是这样的:

  • 每个并发任务都会在 run_source() 里创建自己的 Workflow
  • 每个 Workflow 有自己的 self.usage
  • source_usage 也是每个任务自己的局部变量
  • global_usage 只在主线程的 for future in as_completed(futures) 里合并
# 每个线程:
run_source()
  -> Workflow()
  -> workflow.usage
  -> source_usage

# 主线程:
as_completed(futures)
  -> 拿到某个 source_usage
  -> merge_usage_map(global_usage, source_usage)

现在没有多个线程同时对同一个 Usage 对象执行:

usage.add(other)

所以当前代码的数据统计不会因为 add() 并发写而乱掉。

真正会出问题的是这种写法:(在最后全局统计时)

global_usage = {}

# 多个 worker 线程里同时执行
merge_usage_map(global_usage, workflow.usage)

两个线程同时加同一个模型时,可能出现丢计数。

现在的最后统计:

for future in as_completed(futures):
    title, success, error, usage = future.result()
    merge_usage_map(global_usage, usage)

虽然前面 5 个 worker 是并发跑的,但它们只是各自返回自己的usage,真正合并到 global_usage 的动作,是主线程一个 future 一个 future 地处理。

worker 1 跑完 -> 返回 usage

worker 2 跑完 -> 返回 usage

worker 3 跑完 -> 返回 usage

主线程:

合并 worker 2 的 usage

合并 worker 1 的 usage

合并 worker 3 的 usage

哪个任务先结束,就先汇总哪个;没结束的任务暂时不会汇总。

# 5 个并发任务启动

第 1 本完成 -> add 到 global_usage

第 3 本完成 -> add 到 global_usage

第 5 本还在跑 -> 暂时没 add

第 2 本还在跑 -> 暂时没 add

第 4 本还在跑 -> 暂时没 add

并发执行,串行汇总。

串行汇总? 会不因为前面的某个线程很慢,而卡住后面的线程

as_completed(futures)的特点是:哪个 future 先完成,就先把哪个吐出来。

同时跑:1 2 3 4 5

任务 3 先完成

-> 主线程立刻拿到任务 3 的 usage

-> merge_usage_map(global_usage, 任务3_usage)

-> 线程池空出一个位置,开始任务 6

任务 1 完成

-> 立刻 add 任务 1 的 usage

-> 开始任务 7

任务 5 很慢

-> 它没完成前不会 add 它自己的 usage

-> 但不会阻塞任务 1/2/3/4/6/7/... 的 add

只有一种等待:最后总函数返回前,会等全部 100 个 future 都完成。因为最终全局总合必须包含所有任务。

所以结论是:

当前代码:没有并发问题。

因为全局合并发生在主线程。

add() 本身:不是线程安全的。

最稳的写法是保持现在这个架构:worker 只返回自己的 usage,主线程统一合并。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发
相关文章 更多
WPS 表格打开文件提示格式不兼容怎么处理
WPS 表格打开文件提示格式不兼容怎么处理

遇到WPS表格打开文件提示格式不兼容怎么办?本文教你通过保留副本、另存为转换、修复入口测试及特殊功能排查,安全处理xls/xlsx等格式差异,避免数据丢失。

Lovart中文版网页怎么登录及界面功能介绍
Lovart中文版网页怎么登录及界面功能介绍

新手如何登录Lovart中文版网页?本文详解账号授权步骤,拆解创意工作区、画布预览与对话输入三大核心模块,演示如何用自然语言生成图片及进行局部编辑,助你快速掌握AI设计工具的基础用法。

Windows10安装缺少驱动找不到硬盘解决方案
Windows10安装缺少驱动找不到硬盘解决方案

Windows 10安装时显示“找不到任何驱动器”或提示缺少驱动?本文详解如何通过BIOS确认硬盘状态、核对VMD/RAID存储模式,以及在安装界面正确加载厂商提供的存储控制器驱动(.inf),避免盲目切换设置导致原系统无法启动。

哔哩哔哩移动端怎么关闭自动连播
哔哩哔哩移动端怎么关闭自动连播

刷视频停不下来?教你在哔哩哔哩移动端快速找到并关闭自动连播功能,涵盖播放器控件、合集列表及全局设置入口,有效防止流量偷跑。

Windows10安装后网卡驱动缺失联网修复
Windows10安装后网卡驱动缺失联网修复

Windows 10重装后无法上网?本文详解如何通过设备管理器查看硬件ID,在另一台设备下载正确驱动,并按顺序安装芯片组、有线及无线网卡驱动,快速恢复网络连接。

二狗PPT怎么用模板快速制作PPT
二狗PPT怎么用模板快速制作PPT

想知道二狗PPT怎么用模板快速出稿?本教程详解从选模板、填内容到调整排版的完整流程,助你高效完成工作汇报与项目演示,避免常见排版误区。

会声会影底部字幕裁剪后画面比例失调解决办法
会声会影底部字幕裁剪后画面比例失调解决办法

解决会声会影裁剪视频底部字幕后画面比例失调、人物拉长或出现黑边的问题。从时间轴确认素材、预览窗口检查变形,到保持宽高比缩放及核对输出设置,提供清晰的界面操作指引与替代处理方案。

PixPix Prompt提示词大汇集:50个拿来即用的高质感电商背景提示词
PixPix Prompt提示词大汇集:50个拿来即用的高质感电商背景提示词

精选50条PixPix电商背景提示词,覆盖纯白棚拍、生活方式、材质光影及节日场景。教你如何在替换背景时保持商品真实细节,提升主图与场景图的视觉质感。

PhotoZoom Classic安装配置
PhotoZoom Classic安装配置

学习如何正确安装 PhotoZoom Classic 并配置工作环境。涵盖安装包确认、界面区域识别、放大尺寸与重采样算法设置、输出格式选择及样例验证步骤,适合初次使用该桌面图片放大软件的用户。

音述AI生成音乐音质差该怎么调整参数
音述AI生成音乐音质差该怎么调整参数

本文详解音述AI生成音乐音质不佳时的调整方法,包括如何细化生成描述、逐项调整风格与乐器参数、简化编制以减少混浊,以及检查导出设置,帮助用户获得更清晰的音频结果。

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
IntelliJ IDEA macOS版
IntelliJ IDEA macOS版
Mac

IntelliJ IDEA 是 JetBrains 推出的专业集成开发环境,重点服务于 Java、Kotlin 与 JVM 项目开发。软件集成代码补全、静态检查、重构、调试、测试、版本控制及构建工具,并可借助插件扩展语言和框架支持。

PyCharm macOS版
PyCharm macOS版
Mac

JetBrains PyCharm 是面向 Python 开发者的集成开发环境,提供智能补全、代码检查、重构、调试、测试、版本控制及虚拟环境管理功能。Mac 版兼容 Intel 与 Apple 芯片,核心功能可免费使用。

WebStorm macOS版
WebStorm macOS版
Mac

JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

WINDOWS 更多
IntelliJ IDEA Windows版
IntelliJ IDEA Windows版
Windows

JetBrains IntelliJ IDEA 是以 Java、Kotlin 和 JVM 项目为核心的专业集成开发环境,提供智能补全、代码检查、安全重构、调试、测试、版本控制及构建工具集成。统一发行版的核心功能可免费用于商业和非商业项目,

PhpStorm Windows版
PhpStorm Windows版
Windows

PhpStorm 是 JetBrains 面向 PHP 与现代 Web 开发打造的专业集成开发环境,提供代码补全、静态检查、重构、调试、测试、数据库、版本控制及前端语言支持。Windows 用户可直接下载安装程序,

PyCharm Windows版
PyCharm Windows版
Windows

PyCharm 是 JetBrains 推出的 Python 集成开发环境,提供智能代码补全、错误检查、重构、调试、测试、Git、终端及 Jupyter Notebook 支持。统一版安装后可体验 30 天 Pro 功能,