尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
从AI助手到串口调试:一周编程踩坑与经验复盘
1月19日到1月25日我的工作日志里管这周叫0119-0125。临近春节手里的活其实没少多少反而因为上游排期各种零碎需求全挤在这周。为了不在月底复盘时一脸茫然我给自己加了个任务每天下班前留十五分钟把当天编程过程里最值得记的东西写进心得本。写的时候没觉得有什么今天翻出来一整理发现一周下来踩的坑和想明白的事还真够写一篇长文。这篇就是这周的编程心得汇总内容横跨AI编程助手、异步编程、大数据随手练习和Linux串口编程基本能反映我这周的完整状态。1. 这周为什么开始记账式复盘周记格式与一周时间线1.1 周记不是流水账是给自己的排错索引以前我也写工作日志但写着写着就变成流水账今天做了什么、改了什么、上线了什么全是动词堆叠。这种记录最大的问题是三个月后再翻根本想不起来当时为什么那样写。后来我调整了记录格式改成三栏式心得当时我以为实际发生了什么现在怎么理解异步会降低代码可读性改造后代码量反而更少可读性取决于封装粒度AI写代码不需要测边界条件经常漏AI需要当新人带说实话这种格式一开始写起来很费劲因为你要逼自己回忆我当时怎么想的。但这正是价值所在编程里的坑几乎都不是代码写错而是脑子里对问题的模型建错了。把模型变化记录下来才是真正的积累。这也是我这篇周记能整理成文章的起点。1.2 一周时间线这周到底忙了些什么先放时间线后面每节再展开说细节。日期主题产出0119日常业务脚本 接入AI编程助手日志处理脚本0120-0121用Codex辅助写业务代码审批流数据整理脚本0122异步脚本并发化改造文件下载从8分钟降到不到2分钟0123MapReduce/HDFS编程实践接口响应码分布统计0124Python绘图可视化柱状图、折线图脚本0125Linux UART串口编程 C语言完全数小题 编程规范复习串口回环测试程序、完全数判断程序一天一个主题看起来有点分散。但我觉得这种横向铺开对个人积累是有益的工作日处理实际业务周末补偿底层知识。两者结合反而比一整周只写业务代码更容易形成长期记忆。1.3 复盘的标准哪些值得写、哪些不值得写了一段时间心得后我给自己定了个过滤规则三秒钟能想到答案的问题不记那种问题记下来是浪费笔纸。卡了十五分钟以上才解决的问题必记因为卡住说明某个理解有偏差。从卡住到解决的过程里有转折的重点记。比如我以为是因为A排查半天发现是B这种认知反转最值钱。至于那些运行时报错百度一下改好了的我通常只留一行遇到XXX问题原因XXX方案XXX。没有反转就没有过多铺开的价值。正是这个规则让这周的记录基本都是有信息量的内容而不是一堆操作日志。2. Codex的引入AI编程提示词真正值钱的部分2.1 为什么从反感AI写代码到愿意付费订阅我一直对AI编程助手持保留态度。倒不是觉得它没用而是见过太多人把AI当成更高配的自动补全写完代码自己完全不过脑子。这周因为一个审批流数据整理脚本实在繁琐抱着试一试的心态用了Codex结果比预期好用不少。我说几个真实体验写CRUD接口和对应的DTO转换时它十分钟产出的量我手写要一小时。给一个包含历史遗留字段结构的数据表它能快速生成一套读写代码但字段命名逻辑经常需要我来纠正。真正有价值的场景不是让它写代码而是让它做第一遍翻译把产品描述翻译成代码骨架再由人来填充关键约束。用着用着每天调用量就不够了。我犹豫了一下最后还是订阅了付费版。原因很简单如果它每周能帮你省出三四个小时的机械劳动这个成本就值得。这也是我第一次为编程工具付费订阅。2.2 几个真正能提高AI输出质量的提示词套路这一周我花了大量时间调提示词。总结下来最有用的不是玄学技巧而是几条朴素的规则。第一给项目上下文不要问空泛问题。一开始我这样问帮我写一个用户登录日志的查询接口。它给出的代码能跑但跟我们项目的依赖完全对不上。后来我改成我们项目使用FastAPI路由在app/routers/user.py。现在要为GET /users/{id}增加返回最近7天登录记录的功能需要复用db/session.py里的get_session。请先列出改动点再给出代码改动。效果立刻不一样。AI编程工具的记忆能力很强但它的默认假设是通用场景。你越是把项目里的真实文件名、依赖关系、调用方式写清楚它越能生成贴合实际的代码。第二让AI先出方案再出代码。遇到复杂一点的需求我会在提示词里加一句不要直接写代码先分析这个函数的边界条件有哪些列出实现思路确认后再给我代码。它输出的方案往往会暴露一些我忽略的边界情况比如时间戳为负、输入字符串为空、并发下重复提交等。这些才是写代码时真正的坑。第三把错误日志原样贴进去并附相关代码。以前我习惯自己先猜猜不到再去查。现在我会直接把跑出来的异常栈丢给它程序运行报KeyError: name相关代码是这一段文件路径是app/services/import_service.py。请帮我分析最可能的三点原因并按可能性排序。它给出的排序通常挺靠谱。尤其是编码问题字段名不一致这类常见坑它比搜索引擎快得多。但这不意味着不用查日志AI的分析只能当作排查路线图最终验证还是得自己做。2.3 哪些代码我会逐行复查哪些只扫一眼过用了AI之后我给自己定了一个代码复查分级这也是这周最想分享的东西样板代码、纯数据转换、DTO拼接扫一眼确认没有明显笔误就过。这部分AI做得比较稳。涉及金额、日期时间解析、编码转换的逐行查。AI写的日期解析代码用过datetime.strptime(s, %Y-%m-%d)去解析带时间部分的字符串跑起来之前完全看不出来。这种边界问题必须人工盯。涉及并发、重试、超时的我只把AI当第一版草稿重点自己改。因为我发现AI对超时后是否取消任务部分失败如何处理这类问题的判断经常偏理想化。这周实际踩的一个例子是AI生成了一段文件下载逻辑下载完直接删除源文件却没有校验文件大小是否跟服务器返回的Content-Length一致。结果有个文件下载到一半服务端断连代码以为是成功源文件被删了导致后续重试都没有意义。这种业务语义它完全意识不到只能人来补。3. 异步编程复盘一次数据整理脚本的并发化改造3.1 原来的脚本慢在哪里这周要处理一批从各渠道打包下来的文件大概700多个每个几MB。原脚本是几个月前写的逻辑是循环用requests逐个下载下载后解压、校验、写入目标目录。跑一次大约需要9分钟。慢的原因很清晰网络IO等待占了大头。下载一个文件大部分时间都在等对端响应。用生活类比的话同步下载就像一个人挨个去柜台办业务办完一个下一个才能递材料而异步则像是同一个服务人员先把几十个请求递出去谁先办完谁先回来回来一个再递一个。后者明显把等待时间利用起来了。这类场景不需要上多线程或多进程。因为瓶颈是IO等待不是CPU计算。用asyncio事件循环单线程就能处理大量并发连接。我开始动手改造。3.2 asyncio aiohttp改造的具体过程改造主要分四步第一步把requests换成aiohttp并且复用ClientSession。复用session很重要因为每个session都有连接池建多个等于白搭。代码大致长这样async def fetch_one(session, file_id): url fhttps://xxxx/download/{file_id} async with session.get(url) as resp: data await resp.read() return file_id, data第二步用asyncio.Semaphore(10)控制并发量。一开始我直接gather全部700个任务结果是同类磁盘写入和连接数同时爆炸日志里全是连接被重置。加了一个信号量sem asyncio.Semaphore(10) async def fetch_with_limit(session, file_id): async with sem: return await fetch_one(session, file_id)并发数定在10是我实测下来的折中方案再往上加速度提升有限但出错率明显上升。这个值跟网络环境强相关不建议照抄。第三步超时和重试。单任务超时我用asyncio.wait_for包一层try: return await asyncio.wait_for(fetch_with_limit(session, file_id), timeout20) except asyncio.TimeoutError: return file_id, None然后在外层做一个重试循环第一次失败等1秒重试最多重试两次。这个重试策略对网络波动很有效最终只有两三个文件是彻底失败的。最后收集结果时用await session.close()收尾避免连接泄漏。3.3 三个让我卡壳的细节改造过程中有几个细节每个都让我浪费了不少时间。第一个是Semaphore的创建时机。原来我在全局直接建sem asyncio.Semaphore(10)在某些版本的Python里会报警告。后来挪到事件循环内部创建问题消失。第二个是异常吞噬问题。await asyncio.gather(...)如果某个任务抛异常未完成的task会被销毁但中间有些异常信息会在日志里看得见却定位不到是哪个文件。最后我改成给每个任务单独包try/except把失败的文件ID收集起来统一打印。这个处理方式虽然啰嗦但排查问题的时候能省半小时。第三个是不要在协程里直接session.close()。多个任务共享同一个session我在其中一个协程的finally里写了close结果其他协程试用已关闭连接报了一堆RuntimeError: Session is closed。正确做法是所有任务跑完之后统一关闭。改完的效果很直接全量下载从9分钟降到1分40秒左右后面的解压校验没有变只是下载环节从瓶颈变成了非瓶颈。3.4 对异步的一点新理解这次实践让我对异步编程有了更落地的认知。以前看那些概念总有个模糊印象觉得异步是同时干多件事实际做完后我认为更准确的说法是异步不减少任务的工作量只是在等待过程中把CPU空出来去做别的。它适合IO密集场景对CPU密集场景帮助不大后者反而应该用多进程。还有一点并发数不是越大越好。网络请求这种场景超过某个上限后对端会开始拒绝连接本地的连接池和内存也都会受影响。做这类改造最好留一个并发数配置项从一个保守值开始慢慢调而不是盲目拉满。4. 大数据热身MapReduce实例、HDFS实践与Python绘图4.1 脱离WordCount的MapReduce练习周五在测试集群上做一个小练习统计某天Nginx日志中不同接口URL的响应码分布。之所以不想再写WordCount是因为那个例子太顺利了根本暴露不出问题。我写了一个简单的Mapper把日志按接口响应码组合输出计数1public class ApiStatusMapper extends MapperLongWritable, Text, Text, IntWritable { private Text outKey new Text(); private IntWritable one new IntWritable(1); Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line value.toString(); // 日志格式: timestamp api_url status_code ... String[] parts line.split(\\s); if (parts.length 3) { outKey.set(parts[1] _ parts[2]); context.write(outKey, one); } } }Reducer就是最简单的那种对value累加求和然后输出。整套流程跑下来我最大的感想是MapReduce的价值不在于快而在于把分布式任务的思考方式强制收敛到map-shuffle-reduce三段式。你不需要关心数据在哪台机器上、怎么分批处理只需要定义好map阶段的映射和reduce阶段的汇总。这个约束对写复杂分布式任务反而是一种保护。当然它也暴露了一个明显问题如果数据量不算大直接写个Python脚本跑内存里更快。MapReduce适合的是单机内存放不下、必须分布处理的量级。4.2 HDFS读写的小坑和心得光跑MapReduce还不够我顺手用Python的hdfs库做了一次HDFS读写测试上传几个小文件读取再写回本地。这一折腾踩到了几个典型的坑。第一个是端口混淆。HDFS的RPC端口默认8020和HTTP端口默认9870或50070不是一回事。Python的hdfs库走的是WebHDFS连的是HTTP那个端口。我一开始照着公司文档填了RPC端口连半天连不上。第二个是小文件问题。HDFS的block默认是128MB甚至更大几个几十KB的小文件占用的其实是NameNode的内存。这让我想起网上说的小文件是HDFS的天敌亲自试过之后更有体感。生产环境里很多小日志文件应该先合并成SequenceFile或压缩格式再写进去不能贪图方便直接丢。第三个是权限问题。测试机上用root操作没问题但切到普通用户后默认权限不够写文件会报Permission denied。做实践练习的时候养成先确认当前用户和目录权限的习惯能省很多排查时间。4.3 Python绘图脚本里的中文字体问题数据统计出来之后我想画几张图方便下周做汇报。结果第一张柱状图出来中文标签全变成了一个个方框。原因都知道matplotlib默认字体里没有中文字形。解决方式通常是这样import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False但这里面有个坑Windows下的Microsoft YaHei到了Linux服务器上根本不存在。我在本地画出来没问题传到Linux上一跑又是方框。后来改用matplotlib.font_manager动态查找系统中可用的中文字体from matplotlib import font_manager import matplotlib.pyplot as plt font font_manager.findSystemFonts(fontpaths/usr/share/fonts, fontextttf) for f in font: if CJK in f or WenQuanYi in f or Noto in f: plt.rcParams[font.sans-serif] [font_manager.FontProperties(fnamef).get_name()] break这套逻辑在不同机器上都能用。另外还有一个观念层面的心得画图之前先想清楚图给谁看、要看什么结论。我第一版图把所有接口全部画进去密密麻麻根本没法看。后来只挑Top 10加上其他整张图才变得能直接用于汇报。工具永远是次要的表达的信息才是核心。5. 底层周六Linux UART串口编程与C语言完全数小题5.1 从零写Linux串口程序的关键步骤周六早上本来想睡懒觉结果刷到几个单片机编程的视频又开始折腾串口通信。我手上没有串口设备就用USB转TTL模块把发送和接收短接做一个回环测试。在Linux下写串口程序第一步是确认设备节点。插上USB转TTL后ls /dev/ttyUSB*能看到ttyUSB0如果用的是板载串口通常是ttyS0或ttyAMA0。这个先确认后面所有操作才不会跑偏。第二步是open设备文件。需要注意如果加了O_NDELAYopen会立即返回而且后续read的行为也会受影响可能立刻返回0而不会等待数据。我做回环测试时想让它阻塞等待所以不加这个标志int fd open(/dev/ttyUSB0, O_RDWR | O_NOCTTY); if (fd 0) { perror(open); return 1; }O_NOCTTY的意思是不要把串口设为控制终端这在我们这种场景下是必须的。第三步是配置termios。我用cfmakeraw把串口设成原始模式再设置波特率struct termios tty; memset(tty, 0, sizeof(tty)); cfmakeraw(tty); cfsetispeed(tty, B115200); cfsetospeed(tty, B115200); tty.c_cc[VMIN] 1; // 至少读到1字节才返回 tty.c_cc[VTIME] 5; // 最多等0.5秒 tcsetattr(fd, TCSANOW, tty);这里有个容易踩的坑波特率必须用B115200这种定义好的常量不能直接传一个115200数字进去。我第一次传数字编译没报错但实际串口速率完全不对。另外cfmakeraw之后终端的很多默认行为都没了比如输入回显、信号处理。如果只是想临时读串口这个配置合适但如果要做交互式命令行还得在此基础上重新打开ICANON等标志。最后就是readchar buf[256]; int n read(fd, buf, sizeof(buf)); if (n 0) { write(STDOUT_FILENO, buf, n); }我做回环测试的时候一开始read老是返回0。排查了半天发现就是打开设备时带了O_NDELAY导致非阻塞模式下没有数据就立即返回。去掉之后程序老老实实在那里等数据回环发一串字符这边也都收得到。这个经历让我对串口编程本身不难难的是搞清楚各种标志位组合这个说法有了更深的体会。Linux串口就是一个文件但termios那几十个标志位才是真正的复杂度所在。5.2 C语言完全数小题为什么还要做这种题下午继续复习C语言顺手把经典的完全数编程题写了一遍。题意很简单如果一个数等于它所有真因子之和那它就是完全数。比如6 12328 124714。我第一版用最笨的循环从1遍历到n/2int is_perfect(int n) { if (n 1) return 0; int sum 1; for (int i 2; i n / 2; i) { if (n % i 0) { sum i; } } return sum n; }功能对但n稍微大一点就有点浪费。后面改成只需要遍历到sqrt(n)因为因子成对出现int is_perfect(int n) { if (n 1) return 0; int sum 1; for (int i 2; i * i n; i) { if (n % i 0) { sum i; if (i ! n / i) { sum n / i; } } } return sum n; }这个小题本身不难但我做它的意义在于提醒自己即使是很基础的东西里面也有可优化的思维点。比如循环的上界为什么是sqrt(n)成对因子怎么处理这些恰恰是很多生产代码里性能问题的雏形。顺带复习了一下浮点数比较的坑C语言里double不能直接用比较完全数判断因为全在整数域所以不受影响。但如果在其他算法里遇到浮点数相等判断正确的做法是设一个epsilon比如fabs(a - b) 1e-9。5.3 翻了一遍华为C编程规范印象深的几点周六下午把网上流传的华为C编程规范翻了一遍说是翻其实重点看了几节有几个点印象很深头文件必须有include guard防止重复包含。这个我平时偶尔偷懒看完后决定以后所有头文件都规范写。函数体尽量短一个函数只做一件事。这条看起来像废话但实际写代码时很多长函数就是在不知不觉中膨胀起来的。能用const就尽量用const能不用宏定义常量就不用。宏没有类型检查出了问题极难排查。变量尽量在首次使用的地方定义不要全部堆在函数开头。这能让阅读代码的人更容易理解每个变量的生命周期。这些规范单独拎出来都很简单难的是在写代码的过程中一直保持。我觉得规范最大的价值不是约束聪明人而是保护六个月后的自己。人很容易忘记当时为什么这么写但遵循一套一致的规范至少能让回看代码的人少踩几个坑。6. 留给下周PLC与OpenCV的试探性路线6.1 为什么突然想碰PLC这周在研究家里一个旧设备的时候意外看了一些PLC编程入门基础知识的资料。原本只是好奇却发现组里接下来可能会有产线设备的通信需求。PLC这个东西我以前完全没碰过但它的逻辑跟嵌入式编程有不少相通之处无非是扫描执行、输入采样、输出刷新那一套。下周不打算深挖目标是先用梯形图点一盏灯再看两个西门子S7-1200的简单例子感受一下工业控制里的循环扫描节奏。如果时间充裕再看一眼ST语言。先把看得懂梯形图这件事做到再去想真实项目的通信对接。6.2 OpenCV3入门的三个小目标OpenCV3编程入门这本书在我书架上放了挺久一直没开箱。下周计划只做三件事读入图片并显示、转灰度后做Canny边缘检测、从视频文件里读帧并打印帧率。这三件事都做完才算把入门这个词用了。为什么要从这三件事开始因为它们涵盖了OpenCV最基本的数据结构Mat、图像预处理、视频流处理三条主线。任何一个图像项目都会用到先把这三根柱子立起来后面学什么都快。6.3 复盘工具的一点改进最后说一个关于周记本身的改进想法。下周开始我会在周记表格里加一列回看日期到了标注的那一天再翻一次上周的内容看问题有没有复发。这样做的好处是很多坑踩过一次记住了但过一个月又会踩第二次。加一个明确的回看机制能让记录真正形成闭环。写到这里0119-0125这周的编程心得就整理完了。我个人有个习惯写完周记后不会立刻回看而是过了两三周再翻。那时候大脑已经忘掉细节再看到记录里当时我以为和实际是两栏对照往往能发现自己的思维定势。这也是我执着于记周记的原因。下周的PLC和OpenCV能学成什么样现在也说不好但至少再回头查的时候这周踩过的程序细节不会再烂在脑子里了。
RELATED

相关推荐

Google 工程师揭秘 Loop Engineering:让 Claude Code 与 Codex 自主工作的配置思路

Google 工程师揭秘 Loop Engineering:让 Claude Code 与 Codex 自主工作的配置思路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/8 9:36:03
银河麒麟V10离线安装QGis全攻略:依赖处理与天地图加载

银河麒麟V10离线安装QGis全攻略:依赖处理与天地图加载

简介:本资源面向在银河麒麟操作系统上开展地理信息工作的科研与技术人员,提供QGis 3.10.4的完整离线安装包,解决国产化环境下无网络时无法在线部署GIS软件的难题。压缩包共95个文件,以89个deb安装包为主,涵盖qgis主程序…

📅 2026/10/8 9:36:03
判断对称二叉树:递归与迭代实现及面试避坑指南

判断对称二叉树:递归与迭代实现及面试避坑指南

判断对称二叉树,一道在LeetCode上标着“简单”、但每年面试都能绊倒不少人的题。我第一次刷到它时也以为不就是比较根节点的左右子树相不相等吗,结果真正动手写的时候才发现,要么是空指针异常,要么是递归进入死循环,要…

📅 2026/10/8 9:36:03
MORE NEWS

更多资讯

📰

AI编程助手Skills实战:从零搭建可复用工作流模块

1. 从“skills”这个热词说起:它到底是什么,为什么突然火了最近几个月,不管是在技术社区、开发者群聊,还是各种工具的使用讨论里,“skills”这个词出现的频率高得离谱。如果你只是偶尔刷到,可能会以为它说的…

📰

Manifest V3下浏览器扩展端侧AI推理实战:WebGPU与WASM性能优化

浏览器扩展这个赛道,这两年因为Manifest V3的强制迁移,正在经历一次彻底的重构。以前大家写扩展,逻辑很简单:内容脚本抓DOM,后台脚本发请求,完事。但现在情况变了——越来越多的场景要求数据不出端&#xf…

📰

本地部署AI编程助手:Docker与Ollama实战指南

1. 为什么要在本地跑一个 AI 编程助手 把 AI 编程助手放到自己机器上跑,这件事在两年前还属于"折腾党专属",现在已经变成很多团队的标准动作。原因很直接:代码是敏感资产,把整段业务逻辑贴到外部服务里,心里…

📰

Python环境搭建从零开始:解释器与PyCharm配置避坑全指南

这段时间好几个刚入门的朋友找我聊同一个问题:自己在网上照着教程,装了Python解释器,又折腾了PyCharm,结果写个最简单的print("hello"),要么提示找不到解释器,要么终端和IDE里编译出来的版本对不…

📰

PHP+微信小程序:低成本搭建多用户投票系统全流程

后台私信里问得最多的一类需求就是投票小程序:才艺比赛、商家打榜、年度评优、萌娃评选……活动方希望用户打开微信就能投一票,不用下载App、不用注册账号。找外包开发,报价基本三五千起步,工期还不可控;用现成的SaaS投…

📰

SpringBoot智能出行系统:拼车打车与订单状态机实战解析

最近帮一个同学做毕业设计,项目名字叫“基于SpringBoot的智能出行系统设计与实现”,说白了就是用Java把拼车、打车、订单管理这一整套流程串起来。这个题目在计算机毕设里非常典型,既覆盖分布式缓存、地理位置计算、订单状态机,又…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬