🐍 课堂趣事:当“程序员买房子”变成“服务器买崩溃” —— 一次关于“虚无循环”的实战教学
老师,我的代码提交不了!一直转圈圈……
刷新了,还是不行!
哎?我怎么被卡退出来了???
今天的编程课,上演了一场“意外大戏”。
主角不是别人,正是我们班的 钱宇泽同学 —— 以及他写的一段“让服务器怀疑人生”的代码。😂
📚 故事背景:一道经典的“买房”题
我们平台上有这样一道题,名字叫 《程序员买房子》:
🏠 某程序员开始工作,年薪 N 万元。
他想在北京中关村公馆买一套 60平米 的房子,目前价格是 200万 元。
房子价格每年以 K% 的速度增长。
该程序员不吃不喝,每年攒下 N 万元。
问:第几年 能买得起?
- 如果 20年及以内 能买到,输出最早年份。
- 否则输出'Impossible'。
样例:
- 输入 50, 2 → 输出 5
- 输入 36, 4 → 输出 8
- 输入 10, 10 → 输出 'Impossible'
看起来不难,对吧?
但就是这道题,差点让我的服务器 “原地升天” 🚀💥
💥 事故现场:提交 → 卡死 → 全员掉线
上课到一半,小钱举手:
“老师,我提交后一直转圈,刷了好几次都没反应!”
“其他同学呢?”
“老师,我也卡住了!”
“我直接被退出登录了……”
我第一反应:网络波动? 不对,全员同时卡,不太可能。
第二反应:服务器被攻击了?! 赶紧登录后台……
结果一看监控—— CPU 负载飙到 100%,内存快爆了,日志里疯狂刷着同一个用户的请求……
那个用户正是 钱宇泽。🔍
🧐 罪魁祸首:一段“虚无循环”代码
我点开小钱提交的代码,差点笑出声:
def a(z1, z2):
total = 2000000 # 房价(单位:万?注意!这里写成了元!)
z = z1 * 10000 # 年薪(转换成元)
money = z
year = 1
while money < total:
money += z
year += 1
total = total + total * z2 * 0.01
if year <= 20:
return year
else:
return 'Impossible'
看着好像没大问题?
但同学们,注意看 房价增长的计算位置 —— 它被放在了 while 循环内部,而且在年份递增之后。
更致命的是:小钱输入的测试数据是 10, 10(年薪10万,房价年涨10%)。
我们来模拟一下:
- 第一年:年薪10万,房价200万 → 买不起。
- 第二年:攒了20万,房价涨到220万 → 还是买不起。
- 第三年:攒了30万,房价涨到242万 → 继续买不起。
问题来了:年薪固定10万,房价每年涨10%,永远追不上。
按理说,超过20年就应该输出 'Impossible' 并退出循环。
但是!小钱的 while 条件只写了 money < total,没有任何年份上限判断。
所以当 year 超过20后,他并没有跳出循环,而是继续傻傻地 year += 1,total 继续涨,money 继续慢慢加……
这个循环会一直跑到 房价和年薪都变成天文数字,永远达不到退出条件,直到服务器资源耗尽!
这就是典型的 “虚无循环” —— 也叫 死循环(但比死循环更“温柔”,因为它只是跑不完,但没死锁,只是累死CPU)。😵💫
🔧 修复时刻:加一个“止损线”
我笑着把小钱叫到身边,指着屏幕说:
“你看看,你的循环什么时候才能停下来?”
小钱挠挠头,想了一会儿,突然一拍桌子:
“哦!我应该在循环里判断如果year > 20就直接返回'Impossible',不然就永远跑下去了!”
于是他飞快地修改了代码:
def a(z1, z2):
total = 2000000
z = z1 * 10000
money = z
year = 1
while money < total:
money += z
year += 1
total = total + total * z2 * 0.01
if year > 20: # ✅ 关键的一行!
return 'Impossible'
return year # ✅ 循环正常结束才返回年份
再提交 —— 秒过!✅
服务器负载瞬间恢复正常,全班同学也能继续刷题了。👏
🎯 技术小课堂:为什么你的循环会“跑飞”?
| 问题点 | 原来 | 修改后 |
|---|---|---|
| 循环退出条件 | 只判断 money < total |
同样判断,但额外加年份上限 |
| 年份超限处理 | 循环结束后才判断 year<=20 |
在循环内部提前拦截超限情况 |
| 极端数据(如10,10) | 永远满足 money<total → 死循环 |
一旦 year>20 立刻返回,结束循环 |
核心教训:
凡是涉及“逐年增长”且可能永远达不到目标的循环,一定要设置 最大迭代次数 或 时间上限 作为“保险丝”!
就像家里的电闸,短路了要自己跳掉,不能等到电线烧起来。⚡
😄 课堂花絮:全班反应
- 小钱修改完代码后,全班同学给他鼓掌(其实更想笑)。
- 有同学调侃:“钱宇泽,你是想让老师换服务器吗?”
- 小钱红着脸说:“我下次一定先想好循环会不会停!”
我趁机在黑板上写下金句:
“写循环之前,先问自己三个问题:
1. 它什么时候开始?
2. 它什么时候结束?
3. 如果永远不结束,会发生什么?”**
全班齐声回答:“服务器会炸!” 💥
🌟 老师有话说
钱宇泽同学,虽然你今天“搞垮”了服务器,但老师非常喜欢你这种敢于尝试的精神。
你发现了问题、自己思考、快速修正 —— 这才是真正的编程素养。
而且,正因为你的“意外贡献”,全班同学都深刻地记住了 循环终止条件 的重要性。
这比讲十遍理论都管用!👍
📝 给所有小创客的课后小贴士
- 🛡️ 防御性编程:永远假设输入数据可能是“极端”的(比如年薪很低、房价涨幅很高)。
- ⏳ 加计数器:如果担心死循环,可以在循环里加一个
count,超过10000次就强制退出并报错。 - 🧪 本地先测试:在提交到在线判题系统之前,先用本地环境跑一下极端数据。
- 😂 开心就好:编程中犯错是常态,每一次Bug都是升级的机会!
🎁 最后,送给大家一段“防死循环”模板代码
def safe_loop_example(param):
max_iter = 10000
count = 0
while condition:
# 业务逻辑
count += 1
if count > max_iter:
raise Exception("循环次数过多,可能陷入死循环!")
return result
你可以把它当成“安全气囊”,关键时刻能救命哦!🚗💨
📢 互动时间
你有没有写过类似的“虚无循环”?当时发生了什么好玩的事?
或者,你还能想到什么办法来改进小钱的代码?(提示:可以用for循环限制年份吗?)
欢迎在留言区分享你的故事或想法,我会挑最有趣的在下节课展示!
今天的课就到这里,下次我们讲 递归 —— 放心,递归如果写不好,崩溃的是你自己的大脑,不是服务器 😉
下课!👋🐍
(本文根据真实课堂事件改编,钱宇泽同学已授权发布,并荣获“最佳服务器压力测试员”称号🏅)
请登录后发表评论
登录后你可以点赞、回复其他评论