gpt4 book ai didi

通过 REPL 与阻塞循环交互的 Python 最佳实践

转载 作者:行者123 更新时间:2023-12-04 03:50:20 25 4
gpt4 key购买 nike

我的程序涉及一个阻塞循环。我想在程序运行时使用 python REPL 来修改程序状态。
语境:
我的python代码中经常有一个阻塞循环:

# main.py
import itertools
import time
global_state = 123

if __name__ == "__main__":
print("Starting main loop")
m = 0
for n in itertools.count():
time.sleep(1) # "computation"
global_state += 1
m += 10
print(f"{n=}, {m=}, {global_state=}")
当我在命令行运行这个程序时,我得到如下信息:
$ python -i main.py
Starting main loop
n=0, m=10, global_state=124
n=1, m=20, global_state=125
n=2, m=30, global_state=126
...
循环将运行数小时或数天。有时,在循环运行时,我希望以交互方式修改某些程序状态。例如,我想设置 global_state = -1000m = 75 。但是 loop 函数正在阻塞...
交互式修改程序状态的方法
方法 1:停止并重新启动循环
我可以使用 KeyboardInterrupt 来停止循环。因为我已经用 python 交互标志调用了 -i,所以我可以在交互式 REPL 中修改全局状态。然后我重新启动循环。这是一个简单的方法,但它有缺点:
  • 如果循环修改了全局状态(或有任何副作用),则在引发 KeyboardInterrupt 时全局状态可能会处于不一致状态;异常可能在循环控制流中的任何一点引发,正确处理此异常可能很棘手,尤其是在业务逻辑复杂的情况下。
  • 重新启动循环时,计数器 n 将重置为零。循环使用的其他状态变量(例如 m )也可能被重置或处于不一致的状态。

  • 方法二:使用线程
    我可以将循环包装在一个函数中并使用 threading 在另一个线程中运行该函数:
    def loop():
    print("Starting main loop")
    m = 0
    for n in itertools.count():
    time.sleep(1) # "computation"
    global_state += 1
    m += 10
    print(f"{n=}, {m=}, {global_state=}")
    import threading
    thread = threading.Thread(target=loop)
    thread.start()
    当我调用 python -i main.py 时,我可以使用 REPL 与全局状态交互,因为循环在另一个线程中运行。 loop 函数仍然像以前一样将 print s 转换为 stdout。这种方法的缺点是:
  • 我无法再与循环的本地状态交互(例如,我无法修改 m ),因为本地状态包含在一个函数中。这是一个主要的缺点。
  • 使用线程使程序更加脆弱;线程可能会崩溃,需要小心处理线程中引发的异常。如果线程阻塞、崩溃或挂起,则很难恢复。
  • 停止循环变得更加困难,因为 KeyboardInterrupt 不再是一个选项(相反,我需要与线程“合作”,向它发送一些应该自我终止的信号)。

  • 方法 3:从循环内放入 REPL
    我可以配合循环进入repl:
    import os
    import code
    if __name__ == "__main__":
    ...
    for n in itertools.count():
    ... # business logic
    if os.stat("use_repl.txt").st_size > 0: # file nonempty
    code.interact(local=locals())
    在这里,当我们想要修改状态时,我们使用一个文件向循环发出信号。如果“use_repl.txt”文件非空,则循环然后调用 code.interact 以创建交互式控制台。即使循环包含在函数中,这也有额外的好处。局部变量被加载到交互式控制台中。
    缺点:
  • 在每次循环时读取“use_repl.txt”文件感觉有点笨拙。但是,一个人如何(合作地)向循环发出信号,表明它应该创建一个 REPL?
  • 调用 code.interact 时循环暂停。这与基于 threading 的解决方案不同,后者循环连续运行。这可能是优势也可能是劣势,具体取决于您的用例。
  • code.interact 创建的 REPL 没有 python 的原生交互模式那么精致。例如,制表符完成不再有效。

  • 调用 code.interact 的替代方法是调用 breakpoint 内置函数。另一种选择是调用 break 关键字,退出循环。然后可以修改状态并重新启动循环(如方法 1 中所示),而不必担心 KeyboardInterrupt 会创建不一致的状态。
    问题:
    有没有我错过的方法?所考虑的每种方法都有明显的缺点......是否有关于实现预期结果的最佳实践?

    最佳答案

    调试程序,当你想检查/修改状态时暂停它,然后继续。

    关于通过 REPL 与阻塞循环交互的 Python 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64507143/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com