025、while 循环的正确姿势:死循环预防、哨兵模式、交互式菜单

025、while 循环的正确姿势:死循环预防、哨兵模式、交互式菜单

上周帮一个刚入行的同事排查线上问题,发现他的爬虫脚本跑了三天后把服务器CPU打满了。一看代码,一个while True循环里没有break条件,连个sleep都没有。这种问题在初学者代码里太常见了——while循环看似简单,但用不好就是一颗定时炸弹。

死循环:不是你想停就能停

先看一个典型的“翻车现场”:

# 别这样写!我见过有人把这段代码部署到生产环境
count = 0
while count < 10:
    print("正在处理第", count, "个任务")
    # 这里踩过坑:忘记更新计数器
    # count += 1   # 注释掉这行,循环永远跑不完

这段代码会无限打印“正在处理第 0 个任务”。count永远等于0,条件永远为True。CPU会一直飙升,直到你手动kill进程或者服务器重启。

死循环的三种常见死法:

  1. 忘记更新循环变量——上面那个例子就是典型
  2. 条件永远为True——比如while 1:或者while True:却没有break
  3. 逻辑错误导致条件无法满足——比如while x > 0:但x一直在增加

我自己的经验是:写while循环时,先写退出条件,再写循环体。就像写代码前先想好怎么收尾一样。

# 正确的姿势:先确认退出机制
count = 0
while count < 10:
    print("正在处理第", count, "个任务")
    count += 1  # 这里踩过坑,但这次记住了

哨兵模式:让循环自己喊停

哨兵模式是我最喜欢用的while循环写法。所谓哨兵,就是一个特殊值,当它出现时循环就结束。

# 哨兵模式:用户输入'quit'时退出
while True:
    user_input = input("请输入命令(输入quit退出):")
    if user_input == 'quit':  # 'quit'就是哨兵
        print("收到退出指令,拜拜")
        break
    print("你输入了:", user_input)

这个模式在处理文件读取时特别香:

# 读取文件直到遇到空行(空行就是哨兵)
with open('config.txt', 'r') as f:
    while True:
        line = f.readline()
        if not line:  # 空字符串就是哨兵
            break
        print("配置项:", line.strip())

哨兵模式的核心思想:用一个不可能出现在正常数据中的值作为终止信号。比如处理用户输入时用’quit’,处理数字时用-1,处理字符串时用空字符串。

交互式菜单:while循环的实战场景

命令行工具里最常见的场景就是交互式菜单。我写过不下20个这样的工具,每次都用同一个模板:

def show_menu():
    print("\n=== 系统管理工具 ===")
    print("1. 查看系统状态")
    print("2. 清理缓存")
    print("3. 重启服务")
    print("0. 退出")

def main():
    while True:
        show_menu()
        choice = input("请选择操作:")
        
        if choice == '1':
            print("正在查看系统状态...")
            # 这里踩过坑:忘记加延时,导致CPU占用过高
            # time.sleep(0.1)
        elif choice == '2':
            print("正在清理缓存...")
        elif choice == '3':
            print("正在重启服务...")
        elif choice == '0':
            print("感谢使用,再见!")
            break
        else:
            print("无效选择,请重新输入")

if __name__ == '__main__':
    main()

这个模板我用了好几年,有几个关键点:

  • 菜单显示放在循环里:每次操作完都能看到菜单
  • 用break退出:而不是修改循环条件
  • 处理无效输入:防止用户乱按导致程序崩溃

实战经验:while循环的五个铁律

  1. 永远不要写裸的while True——至少加个sleep或者明确的break条件。我见过最离谱的代码是while True: pass,直接把CPU干到100%。

  2. 哨兵值要选对——处理用户输入时,‘quit’、‘exit’、'q’都要考虑。处理数字时,-1或者0通常是不错的选择。

  3. 循环体内要有延时——特别是轮询场景,比如检查文件是否生成、等待API响应。time.sleep(0.1)就能让CPU从100%降到1%。

  4. 考虑超时机制——有些循环可能因为外部原因永远跑不完。加个超时计数器,超过一定次数就强制退出。

# 超时保护:防止死循环
max_retries = 5
retry_count = 0
while retry_count < max_retries:
    try:
        result = api_call()
        if result:
            break
    except Exception as e:
        print(f"第{retry_count+1}次调用失败:{e}")
        retry_count += 1
        time.sleep(1)
  1. 日志记录——生产环境里的while循环一定要加日志。不然出了问题你都不知道循环卡在哪一步。

个人经验

写while循环这么多年,最大的感悟是:循环越简单越好。复杂的业务逻辑不要塞进循环体,拆成函数。循环只负责“什么时候继续”和“什么时候停止”,具体做什么交给函数去处理。

还有一个容易被忽视的点:while循环里的异常处理。如果循环体里抛了异常没捕获,整个循环就挂了。我习惯在循环体最外层加个try-except,至少保证异常不会让循环意外终止。

最后说一句:能用for循环解决的问题,别用while。for循环天然有边界,while循环需要你自己维护边界。少一个变量就少一个bug源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值