【AI图像生成网站Golang】项目测试与优化
AI图像生成网站
目录
一、项目介绍
二、雪花算法
三、JWT认证与令牌桶算法
四、项目架构
五、图床上传与图像生成API搭建
六、项目测试与优化
六、项目测试与优化
在开发过程中,性能优化是保证项目可扩展性和用户体验的关键步骤。本文将详细介绍我如何使用一些主流的性能评估工具进行项目性能检测,并在此基础上进行优化。
1. 性能评估工具
我使用的性能检测工具如下:
- k6: 用于负载测试的开源工具,可以通过编写简单的javascript测试脚本,模拟高并发场景下的用户行为。
- k6 cloud: 是k6的云服务扩展,能够提供比本地运行更详细的性能监控和分析报告。
- pprof: 用于捕获CPU、内存等的使用情况进行采样分析,帮助定位性能瓶颈
- trace: 可以通过可视化的时间线查看goroutine的执行和调度情况。
在后文中,我们会使用k6运行测试文件,并根据k6 cloud上通过的请求数和RPS(Requests Per Second,每秒请求数)来简单评估性能,之后会使用pprof和trace工具查找性能瓶颈和突破口。
2. 性能评估与分析
测试流程
在进行负载测试之前,我首先进行了单用户的性能测试,用于了解每个请求的处理时长,确保基本功能的正常工作。之后,我模拟了并发场景,逐渐增加并发量测试系统的表现。
使用 k6 进行负载测试
单用户测试: 在单用户场景下,我编写了一个的k6脚本,模拟了一个用户从注册到上传作品的一套API调用流程。
import http from 'k6/http';
import { sleep, check } from 'k6';
import {generateImage, generateRandomPrompt, generateUniqueUsername,generateUniqueEmail} from "./dynamic_data.js";// 配置接口的基本 URL
const BASE_URL = 'http://localhost:8080/api/v1';// 读取 Base64 数据
const base64Image = open("image_base64.txt");// 定义一个变量来跟踪是否正在刷新 token
let refreshing = false;// k6 入口函数
export default function () {// 用户注册信息const USER_CREDENTIALS = {avatar: `data:image/png;base64,${generateImage(base64Image)}`,username: generateUniqueUsername(),password: 'password123',confirm_password: 'password123',email: generateUniqueEmail(),};// 1. 用户注册const res = http.post(`${BASE_URL}/signup`, JSON.stringify(USER_CREDENTIALS), {headers: { 'Content-Type': 'application/json' },});check(res, { 'signup succeeded': (r) => r.status === 200 });// 2. 用户登录const loginRes = http.post(`${BASE_URL}/login`, JSON.stringify(USER_CREDENTIALS), {headers: { 'Content-Type': 'application/json' },});check(loginRes, {'Login succeeded': (r) => r.status === 200,});const accessToken = loginRes.json('data.access_token');const refreshTokenValue = loginRes.json('data.refresh_token');if (!accessToken || !refreshTokenValue) {throw new Error('Login failed, tokens not received');}// 3. 创建分组const genCategory = {cover: `data:image/png;base64,${generateImage(base64Image)}`,category_name: `category_${Math.random().toString(36).substring(2, 15)}`,description: generateRandomPrompt(),};const createGroupRes = apiRequest('POST', `${BASE_URL}/createCategory`, genCategory, accessToken);check(createGroupRes, { 'Create group succeeded': (r) => r.status === 200 });// 4. 浏览分组const groupRes = apiRequest('GET', `${BASE_URL}/category`, null, accessToken);check(groupRes, { 'Browse groups succeeded': (r) => r.status === 200 });const groups = groupRes.json('data');const groupId = groups[0].category_id;// 5. 浏览作品const worksRes = apiRequest('GET', `${BASE_URL}/categoryDetail/${groupId}`, null, accessToken);check(worksRes, { 'Browse works succeeded': (r) => r.status === 200 });// 6. 提交图像处理任务const imageTaskPayload = {ori_image: `data:image/png;base64,${generateImage(base64Image)}`,category_id: groupId,prompt: generateRandomPrompt(),};const processRes = apiRequest('POST', `${BASE_URL}/processImage`, imageTaskPayload, accessToken);check(processRes, { 'Process task submitted': (r) => r.status === 200 });// 7. 上传作品const newWork = {work_image: `data:image/png;base64,${generateImage(base64Image)}`,// work_image: `data:image/png;base64,${genImage}`,category_id: groupId,prompt: generateRandomPrompt(),};const uploadRes = apiRequest('POST', `${BASE_URL}/uploadWork`, newWork, accessToken);check(uploadRes, { 'Upload work succeeded': (r) => r.status === 200 });
}// 刷新 Token 的逻辑
function refreshToken(refreshToken) {const refreshRes = http.post(`${BASE_URL}/refresh_token`, JSON.stringify({ refresh_token: refreshToken }), {headers: { 'Content-Type': 'application/json' },});check(refreshRes, {'Token refreshed': (r) => r.status === 200,});const newToken = refreshRes.json('access_token');if (!newToken) {throw new Error('Failed to refresh token');}return newToken;
}// API 请求方法
function apiRequest(method, url, body, token) {const headers = {'Content-Type': 'application/json',Authorization: `Bearer ${token}`,};let res;if (method === 'GET') {res = http.get(url, { headers });} else if (method === 'POST') {res = http.post(url, JSON.stringify(body), { headers });}// 如果遇到 401 错误,且没有正在刷新 tokenif (res.status === 401 && !refreshing) {console.log('Access token expired, refreshing...');// 设置 refreshing 为 true,避免并发请求时重复刷新refreshing = true;// 刷新 tokenconst newToken = refreshToken(refreshTokenValue);// 刷新完成后,重新发送请求res = apiRequest(method, url, body, newToken);// 刷新完成,重置 refreshing 状态refreshing = false;}return res;
}
测试结果(单用户场景):
点击图中链接即可进入 k6 cloud 界面查看更详细的数据,可以看到单例用户的运行时长为8.3s。
进入可视化界面可以看到,单例用户的总请求为7个,平均响应时间为 4372 ms,失败率为 0% ,每秒请求数(RPS)在 1~2 之间。
在单用户场景下,系统表现良好,响应时间低,且无错误发生。接下来,我开始使用并发用户场景进行测试,模拟“高负载”下的表现(展示实验用的电脑配置低,不能模拟真正的高并发,在此仅做示例
^_^")。
并发测试
在使用之前编写的Python API代码进行并发测试时,出现了报错: Model inference error: index 11 is out of bounds for dimension 0 with size 11
,这时将 Python API 中这一段的 num_inference_steps=10
改小一些即可。
具体原因不在这里占用篇幅,请移步这里查看:解决并发情况下调用 Instruct-pix2pix 模型推理错误
images = pipe(prompt=request.prompt, image=image, num_inference_steps=5, image_guidance_scale=1).images
在之前的代码中加入以下部分即可进行并发测试。这里我使用了 k6 的 constant-arrival-rate
执行器模式来控制请求的速率和并发用户数。
在 constant-arrival-rate
配置下,k6 会持续不断地以固定速率发送请求,在本测试环境下,rate: 5
意味着 k6 会保持每秒发送 5 个请求,直到测试结束。这种配置适合模拟某些稳定的请求负载。
export const options = {scenarios: {my_test: {executor: 'constant-arrival-rate',rate: 5, // 每秒发送 5 个请求duration: '5m', // 持续 5 分钟preAllocatedVUs: 5, // 提前分配的虚拟用户数maxVUs: 10, // 最大虚拟用户数},},
};
当然,除了 constant-arrival-rate
之外,k6 还提供了其他几种执行器模式,适用于不同的负载场景,比如:
virtual-users (VUs):
这是最常见的执行器模式,适用于模拟一群用户的行为,可以模拟不同用户的交替请求。
export const options = {stages: [{ duration: '10s', target: 10 }, // 10 秒内增加到 10 个虚拟用户{ duration: '1m', target: 10 }, // 保持 10 个虚拟用户 1 分钟{ duration: '10s', target: 0 }, // 10 秒内减少到 0],
};
ramping-arrival-rate
这种模式用于模拟请求逐步增加的情况,可以通过配置startRate
(起始速率)、endRate
(结束速率)和 duration
(持续时间)来设置请求的增长速率。
export const options = {scenarios: {my_test: {executor: 'ramping-arrival-rate',startRate: 10, // 初始请求速率每秒 10 个请求endRate: 50, // 最终请求速率每秒 50 个请求duration: '2m', // 持续 2 分钟},},
};
shared-iterations
在这种模式下,所有虚拟用户共同执行相同数量的请求,直到所有请求完成。
export const options = {scenarios: {my_test: {executor: 'shared-iterations',iterations: 100, // 共有 100 次请求vus: 10, // 使用 10 个虚拟用户},},
};
per-vu-iterations
这种模式下,每个虚拟用户会执行一定次数的操作。
export const options = {scenarios: {my_test: {executor: 'per-vu-iterations',vus: 10, // 使用 10 个虚拟用户iterations: 100, // 每个虚拟用户执行 100 次操作},},
};
并发测试完成后,进入 k6 cloud 界面查看测试数据。
可以看出,虽然我使用了 constant-arrival-rate
配置,但是图中的请求数量和响应数量很不稳定。
并且可以观察到,随着并发量的增加,一些需要调用API的接口响应时间明显上升,尤其是 p95 和 p99 。
初步判断是 API 调用部分出现了阻塞。
pprof 分析
使用 pprof 跟踪代码的 CPU 占用率发现,耗时最长的是 net.(*Resolver) lookupIP
,占用了 56.46% 的 CPU 时间。该函数负责 DNS 查询,用于将域名解析为IP地址,解析流程通常包括:
- 本地缓存查询
- 向 DNS 服务器发送请求
- 等待服务器返回解析结果
在项目中,如果短时间内发起大量外部请求,且每次请求都需要进行完整的 DNS 查询流程,将会导致 DNS 查询成为性能瓶颈。
此外,SetupRouter 中的日志记录(19.24%)和身份验证(12.48%)中间件是系统的次要瓶颈。
3. 优化方案
在 Go 中,默认 HTTP 客户端会在每次请求时触发新的 DNS 查询,如果复用 htttp.Client
,则可以有效减少 DNS 查询次数。
同时,将外部 API 调用解耦到 Goroutine 中异步执行,可以让主线程快速处理其他任务,如日志写入等。
我们还需要引入 redis 来缓存一些会重复查询的信息,如已经验证过的用户信息等。
4. 优化实践
4.1 引入 Goroutine 解耦外部 API 调用
之前,外部 API 调用在主线程中直接执行,导致主线程需要等待外部服务返回结果。我们通过以下方式进行优化:
(1)图像上传与处理的异步化:
- 将图像上传和处理 API 任务拆分为两个 Goroutine。
- 使用 Redis 和 RabbitMQ 实现消息队列,将任务放入队列中,由独立的消费者处理,避免主线程阻塞。
- 使用
sync.WaitGroup
和channel
进行任务同步与通信。
var wg sync.WaitGroupwg.Add(3) // 我们要等待两个消费者 goroutinego func() {defer wg.Done()controller.ConsumeUploadTasks("upload_image")}()go func() {defer wg.Done()controller.ConsumeProcessTasks("process_image")}()
(2)HTTP 客户端复用:
- 创建一个全局的
http.Client
,启用连接池复用。
var ossClient *oss.Clientfunc init() {// 确保配置已经加载if err := settings.Init(); err != nil {log.Fatalf("failed to load settings: %v", err)}// 初始化 OSS 客户端配置cfg := oss.LoadDefaultConfig().WithRegion(settings.Conf.Region).WithCredentialsProvider(credentials.NewStaticCredentialsProvider(settings.Conf.AccessKeyID, settings.Conf.AccessKeySecret, ""))// 创建全局 OSS 客户端实例ossClient = oss.NewClient(cfg)
}// UploadImageToOSS 上传图片的函数
func UploadImageToOSS(base64Image string) (string, error) {if strings.HasPrefix(base64Image, "data:image") {base64Image = strings.Split(base64Image, ",")[1]}// 解码 Base64 数据imageData, err := base64.StdEncoding.DecodeString(base64Image)if err != nil {return "", fmt.Errorf("failed to decode base64 data: %v", err)}// 生成文件名objectName := GenerateUniqueFileName("png")// 创建上传对象的请求request := &oss.PutObjectRequest{Bucket: oss.Ptr(settings.Conf.Bucket), // 存储空间名称Key: oss.Ptr(objectName), // 对象名称Body: bytes.NewReader(imageData), // 图片数据}// 上传文件_, err = ossClient.PutObject(context.TODO(), request)if err != nil {return "", fmt.Errorf("failed to upload image to OSS: %v", err)}// 生成文件的 URLurl := fmt.Sprintf("%s/%s", settings.Conf.Endpoint, objectName)return url, nil
}
4.2 身份验证优化
对于身份验证逻辑,我引入了 Redis 缓存来避免频繁查询数据库。
// CacheUserInfo 缓存用户信息
func CacheUserInfo(userInfo map[string]interface{}) error {key := fmt.Sprintf("user_info:%s", userInfo["user_id"])err := client.HMSet(ctx, key, userInfo).Err()if err != nil {return fmt.Errorf("failed to HMSet: %w", err)}err = client.Expire(ctx, key, time.Duration(settings.Conf.RedisConfig.DefaultTTL)).Err()if err != nil {return fmt.Errorf("failed to set expire: %w", err)}// 如果都成功,返回 nilreturn nil}// GetCachedUserInfo 获取缓存的用户信息
func GetCachedUserInfo(userID string) (map[string]string, error) {key := fmt.Sprintf("user_info:%s", userID)return client.HGetAll(ctx, key).Result()
}
4.3 效果测试
在对项目进行优化后,通过 k6 cloud
工具对性能进行对比测试发现,系统的并发能力提升了近 7 倍,总请求数较之前增长了 2.3 倍,系统处理请求的效率得到了显著提升。
项目 | 优化前 | 优化后 |
---|---|---|
总请求数 | 598 | 1.4K |
请求速率峰值(reqs/s) | 6.33 | 44.33 |
95% 的响应时间(ms) | 32132 | 3.3 |
在 k6 可视化界面,可以看到在测试初期,请求速率(RPS)和响应时间会快速上升到一个较高的峰值。这说明系统能够快速响应并处理高并发请求。
峰值过后,请求速率和响应时间会迅速下降到一个较低的数值,并且请求速率始终保持一定的小幅波动。这是因为在高并发情况下,CPU 和内存资源的分配会随着请求数量的波动而调整,导致 RPS 的小幅变化。
在优化前,系统中耗时最多的四个请求占用大量时间,优化后有了显著的降低。
DNS 查询的 CPU 占用率从 56.46% 降低到 21.16% 。
主线程负载显著减轻,高耗时任务被转移到 Goroutine 中异步处理。
在 trace 可视化界面中,能看到Goroutines 使用数量平稳,分布较为均匀,未出现 Goroutine 阻塞的尖峰现象。同时运行的 Goroutines 数量略高,但在合理范围内。
Heap 的内存分配曲线波动较大,但回收相对及时,未出现内存泄漏或超量分配的现象。GC 活跃,Heap 内存峰值控制在可接受范围。
Threads 数量略高,可能与 HTTP 客户端连接池、Redis 以及 RabbitMQ 的 I/O 操作相关。
GC 曲线与 Heap 使用曲线基本同步,垃圾回收频繁但时间较短。未来会考虑进一步优化数据结构设计,避免频繁分配临时对象。
网络 I/O 分布均匀,RabbitMQ 和 Redis 的使用改善了对数据库的直接依赖。外部 API 调用已异步化,但响应时间稍长。
对各个 Proc,PU 核心的使用较为均匀,任务分配合理。Goroutine 与 Proc 的调度平衡较好,未观察到 Proc 长时间空闲。
在未来的工作中,将会考虑尝试将 RabbitMQ 的消费者分布式部署,以进一步增加并发量。
相关文章:

【AI图像生成网站Golang】项目测试与优化
AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构 五、图床上传与图像生成API搭建 六、项目测试与优化 六、项目测试与优化 在开发过程中,性能优化是保证项目可扩展性和用户体验的关键步骤。本文将详细介绍我如何使用一…...

vue常用自定义指令
参考链接1https://blog.csdn.net/m0_67584973/article/details/139300966?spm1001.2014.3001.5501 参考链接2https://juejin.cn/post/7067051410671534116...

以太网帧、IP数据报图解
注:本文为 “以太网帧、IP数据报”图解相关文章合辑。 未整理去重。 以太网帧、IP数据报的图解格式(包含相关例题讲解) Rebecca.Yan已于 2023-05-27 14:13:19 修改 一、基础知识 UDP 段、IP 数据包,以太网帧图示 通信过程中&…...

01.大模型起源与发展
知识点 注意力机制(Attention)的主要用途是什么? 选择重要的信息并忽略不相关的信息 Transformer 模型是基于什么理论构建的? C. 注意力机制(Attention) GPT 和 BERT 的主要区别是什么? C. GPT…...

leetcode刷题日记03——javascript
题目3: 回文数https://leetcode.cn/problems/palindrome-number/ 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 回文数是指正序(从左向右)和倒序(从右向…...

vue横向滚动日期选择器组件
vue横向滚动日期选择器组件 组件使用到了element-plus组件库和dayjs库,使用前先保证项目中已经下载导入 主要功能:选择日期,点击日期可以让此日期滚动到视图中间,左滑右滑同理,支持跳转至任意日期,支持自…...
【大模型】大模型项目选择 RAGvs微调?
RAG 输入问题,在知识库匹配知识,构建提示词:基于{知识}回答{问题} 微调 用知识问答对重新训练大模型权重,输入问题到调整后的大模型 如何选择 如果业务要求较高,RAG和微调可以一起使用 1-动态数据 选择RAG 原因&a…...
2024年12月CCF-GESP编程能力等级认证Python编程一级真题解析
本文收录于专栏《Python等级认证CCF-GESP真题解析》,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(每题 2 分,共 30 分) 第 1 题 2024年10月8日,诺贝尔物理学奖“意外地”颁给了两位计算机科学家约翰霍普菲尔德(John J. Hopfield)和杰弗里辛顿(Geof…...
【机器学习】元学习(Meta-learning)
云边有个稻草人-CSDN博客 目录 引言 一、元学习的基本概念 1.1 什么是元学习? 1.2 元学习的与少样本学习的关系 二、元学习的核心问题与挑战 2.1 核心问题 2.2 挑战 三、元学习的常见方法 3.1 基于优化的元学习 3.1.1 MAML(Model-Agnostic Meta…...

详解Redis的String类型及相关命令
目录 SET GET MGET MSET SETNX SET和SETNX和SETXX对比 INCR INCRBY DECR DECRBY INCRBYFLOAT APPEND GETRANGE SETRANGE STRLEN 内部编码 SET 将 string 类型的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么…...

android RadioButton + ViewPager+fragment
RadioGroup viewpage fragment 组合显示导航栏 1、首先主界面的布局控件就是RadioGroup viewpage <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools…...
给机器装上“脑子”—— 一文带你玩转机器学习
目录 一、引言:AI浪潮中的明星——机器学习 二、机器学习的定义与概念 1. 机器学习与传统编程的区别 2. 机器学习的主要任务类型 3. 机器学习的重要组成部分 三、机器学习的工作原理:从数据到模型的魔法之旅 1. 数据收集与预处理——数据是机器的…...

论文笔记:是什么让多模态学习变得困难?
整理了What Makes Training Multi-modal Classification Networks Hard? 论文的阅读笔记 背景方法OGR基于最小化OGR的多监督信号混合在实践中的应用 实验 背景 直观上,多模态网络接收更多的信息,因此它应该匹配或优于其单峰网络。然而,最好的…...

ChatGPT Search开放:实时多模态搜索新体验
点击访问 chatTools 免费体验GPT最新模型,包括o1推理模型、GPT4o、Claude、Gemini等模型! ChatGPT Search:功能亮点解析 本次更新的ChatGPT Search带来了多项令人瞩目的功能,使其在搜索引擎市场中更具竞争力。 1. 高级语音模式&…...
Centos7.9 离线安装docker
实验环境: [root192 ~]# cat /etc/system-release CentOS Linux release 7.9.2009 (Core)下载二进制压缩包 a. 官网下载地址: https://download.docker.com/linux/static/stable/x86_64/b. 阿里云下载地址 https://mirrors.aliyun.com/docker-ce/lin…...

C语言函数在调用过程中具体是怎么和栈互动的?
从栈开始的一场C语言探险记 —— C语言函数是如何与栈"共舞"的。 栈的舞步解析 通过一个简单的例子来看看这支"舞蹈": int add(int a, int b) {int result a b;return result; }int main() {int x 10;int y 20;int sum add(x, y);retur…...

【Java中常见的异常及其处理方式】
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” 文章目录 字符串修改的实现——StringBuilder和StringBuffer异常常见异常①算数异常②数组越界异常③空指针异…...
如何更新项目中的 npm 或 Yarn 依赖包至最新版本
要升级 package.json 文件中列出的包,你可以使用 npm(Node Package Manager)或 yarn。以下是两种工具的命令来更新你的依赖项: 使用 npm 更新所有包到最新版本 npm update如果你想将所有依赖项更新到其各自最新的大版本…...

SpringBoot3整合FastJSON2如何配置configureMessageConverters
在 Spring Boot 3 中整合 FastJSON 2 主要涉及到以下几个步骤,包括添加依赖、配置 FastJSON 作为 JSON 处理器等。下面是详细的步骤: 1. 添加依赖 首先,你需要在你的 pom.xml 文件中添加 FastJSON 2 的依赖。以下是 Maven 依赖的示例&#…...

《Vue3实战教程》2:Vue3快速上手
如果您有疑问,请观看视频教程《Vue3实战教程》 快速上手 线上尝试 Vue 想要快速体验 Vue,你可以直接试试我们的演练场。 如果你更喜欢不用任何构建的原始 HTML,可以使用 JSFiddle 入门。 如果你已经比较熟悉 Node.js 和构建工具等概念…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...

DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...

qt+vs Generated File下的moc_和ui_文件丢失导致 error LNK2001
qt 5.9.7 vs2013 qt add-in 2.3.2 起因是添加一个新的控件类,直接把源文件拖进VS的项目里,然后VS卡住十秒,然后编译就报一堆 error LNK2001 一看项目的Generated Files下的moc_和ui_文件丢失了一部分,导致编译的时候找不到了。因…...