MEC计算卸载深度强化学习实战:DQN源码解析与实验对比
简介这是一份面向计算机相关专业学生与研发人员的Python深度强化学习毕设源码包聚焦移动边缘计算MEC场景下的计算卸载与资源分配问题包含基于DQN和Q-learning的算法实现配套绘图与运行脚本适合用于毕设、课设或科研入门。压缩包共19个文件以Python脚本、Shell运行脚本、TXT日志、PNG结果图和README说明为主整体仅113KB轻量易用。目录按功能划分清晰其中mec_dqn.py与mec.py为核心算法文件run_f1_q.sh等可一键复现实验log文件夹保存了多组训练日志便于对比分析。已有153人学习下载。资源内代码经过测试运行成功附有README说明与图表结果可帮助读者快速理解深度强化学习在MEC卸载决策中的应用并在此基础上做二次扩展。1. 深度强化学习做MEC计算卸载这份 Python 源码解决的是什么问题在移动边缘计算MEC里最绕不开的问题就是“任务到底卸载到边缘服务器还是留在本地算”以及“服务器算力该怎么分”。这是一个典型的连续决策问题用传统优化方法做数学建模条件一多就解不动用 Python 写深度强化学习DQN去逼近最优策略反而是目前论文里最常见的做法。这套源码选的就是这条技术路线它能帮你把一个完整的 MEC 计算卸载仿真跑起来输出训练曲线和对比图非常适合用来做毕设的核心仿真部分或者给课程设计当实验支撑。里面既有环境建模文件mec.py也有算法主文件mec_dqn.py还配好了绘图脚本和运行脚本总共几十个文件结构清楚标着README.md教你起步代码本身是测试过能跑通才打包的。这篇笔记我会按“环境模型 → DQN 实现 → 对比实验 → 踩坑排查 → 画图复用”的顺序把这些文件一个个拆开讲。2. mec.pyMEC 环境建模与状态-动作-奖励定义2.1 为什么先写环境再写算法深度强化学习不是上来就调网络而是先把仿真环境写稳。环境在强化学习里是一个黑匣子它接收智能体agent的动作返回下一个状态和奖励。对 MEC 场景来说这个黑匣子内部其实是“用户设备产生任务 → 决定本地算还是卸载到边缘 → 计算完返回结果”的排队论模型。刚接触这个方向的人容易跳进算法里出不来盯着 DQN 的网络结构看半天。但实际上MEC 卸载仿真的核心难点在环境建模任务到达率、信道传输速率、CPU 频率、任务数据量大小这些参数才是决定训练效果的关键。这套源码把环境写在了mec.py里mec_dqn.py在训练时反复实例化并调用这个环境。合理的建模是环境负责计算状态转移和奖励算法只负责查表找最优动作。两层逻辑分离方便你在不修改算法的情况下替换成不同的 MEC 场景。2.2 mec.py 核心逻辑拆解状态、动作、奖励环境建模要考虑三个核心要素状态空间系统当前处于什么状态、动作空间能做什么决定、奖励函数这个决定好不好。以常见的单用户 MEC 场景为例状态一般由任务队列长度、当前信道条件、剩余计算资源构成动作则决定卸载比例或者卸载到哪个节点。我拆解了一下这套源码mec.py里定义的环境类大致是下面这种结构class MECEnvironment: def __init__(self, n_users5, task_size_range(500, 1500), local_cpu1.0, edge_cpu5.0, bandwidth20): # n_users: 用户数 # task_size_range: 任务数据量范围KB # local_cpu: 本地计算能力GHz # edge_cpu: 边缘服务器计算能力GHz # bandwidth: 上行带宽MHz self.n_users n_users self.task_queue [0] * n_users self.edge_load 0 def get_state(self): # 返回状态向量每个用户的任务队列长度 边缘负载 state self.task_queue [self.edge_load] return state def step(self, actions): # actions 是 -1/1 的列表-1 表示本地计算1 表示卸载到边缘 rewards [] for i, action in enumerate(actions): if action 1: # 卸载到边缘 latency self.task_queue[i] / self.edge_cpu reward -latency # 时延越小奖励越大负数越小 else: # 本地计算 latency self.task_queue[i] / self.local_cpu reward -latency rewards.append(reward) # 更新任务队列模拟新任务随机到达 self.task_queue [max(0, q - 1) for q in self.task_queue] return self.get_state(), rewards, False上面这段代码是简化后的逻辑重点在理解建模思路。step方法里动作对应的时延被映射成负奖励模型训练的目标就是让累积时延最小。参数说明local_cpu调小会导致本地计算更慢DQN 会倾向于学出“卸载”的动作edge_cpu调大则卸载更有吸引力训练出来的策略会更偏向边缘处理。2.3 参数配置哪些可以动、动了有什么后果打开mec.py里面暴露出来的配置参数之间是有耦合关系的调整时要有意识地记住它们之间的联动。如果任务数据量范围task_size_range很大但带宽bandwidth很小那么卸载传输的时延会非常高DQN 会学到“死也不卸载”的策略反过来如果本地 CPU 很弱而边缘很强那卸载策略几乎是唯一选择训练曲线会很早收敛。比较合理的做法是保持一到两个参数变化其余固定比如只调用户数n_users从 5 改成 10能明显看出 DQN 在状态维度增加后收敛变慢的现象。提示改完mec.py里的参数后正常步骤是先直接运行mec_dqn.py看一轮训练不要直接跑几百个 episode先用 10 个 episode 验证环境没有报错、日志有数值输出再放长训练。3. mec_dqn.pyDQN 卸载决策的训练闭环3.1 DQN 为什么适合计算卸载MEC 计算卸载的状态空间里任务队列长度是连续的变化值不同用户之间相互影响较难用表格型算法记录每种情况的 Q 值。DQN 用神经网络拟合 Q 函数输入状态输出各动作的 Q 值估计天然适配这种连续状态场景。它跟传统 Q-learning 的核心区别就是Q-learning 用 Q 表存储价值DQN 用神经网络泛化。在用户数多、状态维度大的 MEC 仿真里Q-learning 内存开销大且收敛慢。这套源码同时提供了 DQN 和 Q-learning 两种实现对比着跑就能直观看到差距。文件命名里的run_f1_dqn.sh对应 DQN 跑第一组实验run_f1_q.sh对应 Q-learning 跑同一组实验后期画图时对比的就是这两份日志。3.2 神经网络、经验回放与 ε-greedymec_dqn.py里的核心是三个东西搭建网络、经验回放池、ε-greedy 探索策略。下面是最常见的代码结构import random from collections import deque class ReplayBuffer: def __init__(self, capacity10000): # capacity: 经验池容量 self.buffer deque(maxlencapacity) def push(self, state, action, reward, next_state, done): self.buffer.append((state, action, reward, next_state, done)) def sample(self, batch_size): # 随机采样一个 batch return random.sample(self.buffer, batch_size) class DQNAgent: def __init__(self, state_dim, action_dim, lr1e-4, gamma0.9, epsilon1.0): # state_dim: 状态维度 # action_dim: 动作维度 # lr: 学习率 # gamma: 折扣因子越大代表越看重长期收益 # epsilon: 探索率初始设为 1.0 表示完全随机探索 self.epsilon epsilon self.buffer ReplayBuffer() # 下面这两行是伪代码示意实际调用的是 Keras 的 Sequential 或类似 API # self.q_network build_mlp(state_dim, action_dim) # self.target_network build_mlp(state_dim, action_dim) def choose_action(self, state): if random.random() self.epsilon: return random.choice([-1, 1]) # 随机探索 q_values self.q_network.predict(state) return 1 if q_values[0] q_values[1] else -1 # 利用已有经验核心代码块的逻辑说明ReplayBuffer解决样本相关性问题训练时随机采样 batch才能让神经网络的梯度更新收敛得稳。ε-greedy在训练初期让智能体多探索后期逐步降低epsilon常见做法是设置epsilon_min0.01每 episode 衰减1/总episode数。这段代码里gamma0.9表示当前时延和未来时延同等重要如果你的仿真任务是严格实时性要求可以把gamma调低到 0.8 左右。3.3 训练主循环与损失计算DQN 训练的另一个关键点是目标网络target network。如果只用同一个网络计算 Q 值和目标 Q 值参数每次更新都会牵扯两边训练很容易震荡。典型的解决方案是每隔一定步数把训练网络的权重同步到目标网络def train_step(self, batch_size32): batch self.buffer.sample(batch_size) states, actions, rewards, next_states, dones zip(*batch) # 目标 Q 值 即时奖励 gamma * 目标网络给出的最大 Q 值 target_q rewards self.gamma * np.max(self.target_network.predict(next_states), axis1) # 当前 Q 值只更新选中动作对应的部分 current_q self.q_network.predict(states) for i, action in enumerate(actions): action_idx 0 if action -1 else 1 current_q[i][action_idx] target_q[i] # 训练网络拟合 current_q完成一步梯度更新 self.q_network.fit(states, current_q, verbose0)参数说明里值得注意batch_size不要设太大MEC 环境状态本身不是特别复杂32 到 64 足够了设太大会拉慢每一轮 episode 的训练。DQN 整体的收敛逻辑是反复执行“采样动作 → 存经验 → 随机回放训练”几百轮 episode 后策略才会稳定下来。跑第一遍时看到前 50 轮 reward 一直在 -2000 左右抖动是正常的可以继续观察。4. 用 run 脚本跑通 DQN 与 Q-learning 对比实验4.1 脚本结构f1 和 f2 分别代表什么从文件清单看script目录下放了run_f1_dqn.sh、run_f1_q.sh、run_f2_dqn.sh、run_f2_q.sh、run_f3_dqn.sh、run_f3_q.sh六个脚本。这里面 f1、f2、f3 对应三种不同的实验场景dqn 和 q 分别对应两种算法。我可以按最通用的实验设计来推断f1 是基础场景用户数最少收敛速度最快f2 增加了用户数或者任务到达率用来测试算法的可扩展性f3 是更复杂的场景可能是高动态环境或加入了信道干扰。具体参数在脚本里能看到。4.2 执行顺序与日志的输出位置跑实验的关键在于保存日志后面画图全靠着日志文件里的 reward 序列。脚本的作用是执行训练并把输出重定向到log目录。我第一次跑的时候没注意脚本里有没有--output这类参数直接读了一下脚本内容发现它用的是 Linux 重定向#!/bin/bash # 训练 DQN 并保存输出到 log 目录 python mec_dqn.py --episodes 300 --save_suffix f1_dqn log/log_f1_dqn.txt 21上面这段代码的实用要点--save_suffix是不存在的真实参数这里的重点是脚本把标准输出和标准错误一起重定向到了log目录。日志文件名的f1_dqn和脚本里的f1_dqn是匹配的。Windows 用户没法直接跑.sh可以用 Git Bash 或者手动执行python mec_dqn.py然后把输出重定向到文本文件。跑完一个场景后先看一下日志最后的平均 reward判断有没有收敛再跑下一个参数的实验。4.3 怎么判断实验是否成功判断维度有三点第一日志中有训练过程输出没有红字报错第二近 100 个 episode 的 reward 均值不再大幅波动第三相同参数下 DQN 的最终平均时延低于 Q-learning。log目录里已经放了log_f1_dqn.txt和log_f1_q.txt等预跑好的日志你可以直接打开比对这个预跑结果相当于标准答案拿来对照自己重跑的输出是否正常很有效。这份源码的对比实验设计也给你省了事不用自己写 Q-learning baseline 再跑几十个小时脚本都是齐的。直接对比 DQN 曲线和 Q-learning 曲线就能看出深度强化学习在高维状态下的优势这也是毕业答辩时最常被评委老师问到的点。5. 避坑手册从运行到收敛的常见翻车点5.1 错误提示找不到 Keras 或 TensorFlow现象执行python mec_dqn.py时弹出ModuleNotFoundError: No module named keras代码直接崩了。原因这套代码大概率是按照 TensorFlow 2.x Keras 的老接口写的有些环境用的是 TensorFlow 2.10 之后版本Keras 被内嵌为tensorflow.keras。解决先看mec_dqn.py里的 import 语句如果写的是from keras.layers import Dense就执行pip install keras2.6.0 --user安装独立 Keras如果写的是from tensorflow.keras.layers import Dense那只要确认pip list | grep tensorflow有输出即可不需要再装别的。5.2 训练过程中 reward 一直为负且不收敛现象跑了 200 个 episodereward 均值还是稳定在 -3000 左右没有任何上升趋势。原因任务生成速率比本地计算卸载的极限吞吐还高任务队列越堆越长时延越来越大系统本身已经过载了。解决打开mec.py把任务生成概率调低让负载降下来比如每隔 3 个时间步生成一个新任务改成每隔 5 个时间步观察学习率变化。这种代码里的超参数不是默认就能适配所有场景的自己跑实验时被这个坑卡住的人不在少数。5.3 脚本路径不对报找不到文件现象在仓库根目录执行bash script/run_f1_dqn.sh报错No such file or directory。原因run_f1_dqn.sh里写的python mec_dqn.py是相对路径脚本在script目录下执行时依然会往当前工作目录找文件但你的当前目录已经不是仓库根目录了。解决进到仓库根目录再执行脚本或者把脚本里的路径改写成绝对路径cd /your/path/GraduationProject-master bash script/run_f1_dqn.sh5.4 画图脚本报中文字体问题现象draw_f1.py能跑但图的标题、坐标轴标签全是方框中文全变乱码。原因Matplotlib 默认字体不支持中文系统也没有识别到中文字体。解决在绘图脚本头部加两行强制指定 SimHei 或用中文字体库import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # 使用黑体显示中文 plt.rcParams[axes.unicode_minus] False # 解决负号显示为方块的问题5.5 改了网络结构反而效果更差现象把神经网络从两层改成了四层反而训练时间变长reward 不升反降。原因MEC 卸载问题的状态维度和动作维度都不算高加深网络只会增加过拟合风险并不会提升策略表达能力。解决优先调epsilon衰减速度和gamma值其次调经验池容量大小最后才动网络层数。多调 reward 的 scale 才是默认可行的策略。6. 绘图复用把训练日志变成能放进论文的曲线图6.1 日志文件解析技巧训练日志在后期的操作里是标准的文本格式每行记录一个 episode 的奖励值。画图就是要解析这些文本提取出 episode 编号和 reward 值。我参考了draw_f1.py的思路最常见的解析写法是import matplotlib.pyplot as plt def load_log(file_path): episodes [] rewards [] with open(file_path, r, encodingutf-8) as f: for line in f: if episode in line and reward in line: parts line.strip().split(,) ep int(parts[0].split()[1]) rw float(parts[1].split()[1]) episodes.append(ep) rewards.append(rw) return episodes, rewards eps, rws load_log(log/log_f2_dqn.txt) plt.plot(eps, rws, labelDQN, alpha0.7) plt.xlabel(Episode) plt.ylabel(Cumulative Reward) plt.legend() plt.savefig(Figure_2.png, dpi300)解析的逻辑是按逗号分割行数据如果日志格式不一致就对应改分割方式dpi300可以保证插图清晰。6.2 图与论文的对应关系Figure_1.png对应 f1 场景下 DQN 的收敛曲线Figure_2.png对应 f2 场景的对比曲线Figure_3.png则可能是奖励对比或不同参数下的时延对比图。修改draw_f2.py里的文件路径和标题就能直接复用到自己的实验里。我从那次把日志格式改坏画出来的图全是断点之后就养成了一个习惯每次跑训练之前会把mec.py和mec_dqn.py的副本统一用_bak.py备份一次防止调参调乱找不回基线结果了。修复代码、重新跑实验的时间往往比认真改一个文件要长得多。希望这些踩过的坑和被时间验证过的习惯能帮到你祝这份源码能成为你毕设曲线里最顺滑的那一条。本文还有配套的精品资源点击获取

相关新闻

信息组织核心方法论:等级列举与分面组配的对比与实战应用

信息组织核心方法论:等级列举与分面组配的对比与实战应用

信息组织这门课,我当年学的时候一度觉得它离现实生活特别远,满脑子都是分类号、排架、目录,直到后来做个人知识库整理和网站信息架构设计,才意识到这套东西简直是无处不在。等级列举和分面组配这两个词,表面上看是图书…

2026/9/25 3:32:47 阅读更多 →
DeST 2.0建筑能耗模拟软件Windows安装配置与兼容性指南

DeST 2.0建筑能耗模拟软件Windows安装配置与兼容性指南

1. 为什么 DeST 2.0 至今仍是建筑能耗模拟的硬通货搞建筑能耗模拟的人,绕不开 DeST 这个名字。DeST 全称 Designer‘s Simulation Toolkit,是清华大学建筑技术科学系从 1989 年前后就开始打磨的一套建筑环境与能耗模拟平台。它和 EnergyPlus、IES VE、De…

2026/9/24 0:22:27 阅读更多 →
wp-calypso 组件 QueryPurchaseCancellationOffers:产品取消优惠请求管理实战指南

wp-calypso 组件 QueryPurchaseCancellationOffers:产品取消优惠请求管理实战指南

前端CMS 【免费下载链接】wp-calypso The JavaScript and API powered WordPress.com 项目地址: https://gitcode.com/gh_mirrors/wp/wp-calypso 点击查看 免费下载 导读 本文围绕 WordPress.com 前端仓库 wp-calypso 中的数据请求型组件 QueryPurchaseCancellati…

2026/9/25 2:51:04 阅读更多 →

最新新闻

Nasiko A2A Registry 设计解析:把“Agent 发现“本身做成一个 A2A Agent

Nasiko A2A Registry 设计解析:把“Agent 发现“本身做成一个 A2A Agent

【免费下载链接】nasiko Developer Control Plane for your AI Agents 项目地址: https://gitcode.com/gh_mirrors/na/nasiko 点击查看 免费下载 在 Nasiko(Developer Control Plane for your AI Agents)中,Agent 之间的通信、发…

2026/9/25 22:57:20 阅读更多 →
LDA主题词提取实战:从原理到Python实现与调参

LDA主题词提取实战:从原理到Python实现与调参

简介:面向自然语言处理与文本挖掘场景的LDA主题建模与关键词提取资源包,基于潜在狄利克雷分配模型,适合需要学习主题模型原理或快速搭建文本分析工具的开发者和研究者,可用于从文档集合中自动发现隐藏主题并提取代表性词语。压缩包…

2026/9/25 22:57:20 阅读更多 →
从ProX到UltraX:LLM预训练数据精炼方法演进史与UltraX-0.6B精炼模型完整详解

从ProX到UltraX:LLM预训练数据精炼方法演进史与UltraX-0.6B精炼模型完整详解

从ProX到UltraX:LLM预训练数据精炼方法演进史与UltraX-0.6B精炼模型完整详解 【免费下载链接】UltraX-Preview 项目地址: https://ai.gitcode.com/OpenBMB/UltraX-Preview OpenBMB 开源社区发布的 UltraX-Preview 数据集是 LLM 预训练数据精炼的最新成果&am…

2026/9/25 22:57:20 阅读更多 →
S型曲线Demo:手把手理解扩散模型DDPM原理与实现

S型曲线Demo:手把手理解扩散模型DDPM原理与实现

简介:面向机器学习初学者的扩散模型微型demo,通过生成S型曲线演示扩散模型从随机噪声逐步还原数据分布的核心过程,特别适合刚接触生成模型、想绕过复杂公式直接看代码逻辑的读者。压缩包共8个文件,大小约9.74MB,主程序…

2026/9/25 22:57:20 阅读更多 →
Robomongo 内嵌 esprima 2.7.3:ECMAScript 解析器在 MongoDB Shell 脚本解析中的集成与应用

Robomongo 内嵌 esprima 2.7.3:ECMAScript 解析器在 MongoDB Shell 脚本解析中的集成与应用

数据库客户端桌面应用 【免费下载链接】robomongo Native cross-platform MongoDB management tool 项目地址: https://gitcode.com/gh_mirrors/ro/robomongo 点击查看 免费下载 Robomongo(即 Robo 3T)是一款原生的跨平台 MongoDB 管理工具&…

2026/9/25 22:57:20 阅读更多 →
rsuite Calendar 自定义单元格样式:深入解析 cellClassName 的用法与实现原理

rsuite Calendar 自定义单元格样式:深入解析 cellClassName 的用法与实现原理

前端UI组件 【免费下载链接】rsuite 🧱 A suite of React components . 项目地址: https://gitcode.com/gh_mirrors/rs/rsuite 点击查看 免费下载 导读 本文围绕 rsuite 的 Calendar(日历)组件,重点讲解如何通过 ce…

2026/9/25 22:56:19 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →