0

我经常看到的一个问题,但尚未找到适合我的问题的解决方案。因此,我希望能得到一些帮助来改进我的代码和我对 Python 的理解。

我正在处理一大块以语法进化为特色并在几个嵌套(目前不可避免)类中运行的代码。

基类(Genetic)处理种群,种群的每个成员都是个体类的一个实例,并使用算法类进行评估。为避免过于复杂 - 代码在多个层中运行(将 Spice 模拟添加到混合中)并运行......相当长的时间 - 有时是几个小时。

这就是我开始寻找一种解决方案的原因,该解决方案允许我以一种不会搞砸一切的方式停止执行。如果我使用通常的 ctrl+c 选项,它只会破坏一切并迫使我重新启动内核并丢失所有数据。

我正在考虑在代码中添加一种监视器,允许我输入按键序列,然后说“好的,我看到你想要完成,我将简单地完成当前的评估循环并退出” .

我相信我不能使用键盘中断,因为这会立即退出代码执行。如果检测到密钥,我更有可能需要一个会改变的标志....

任何帮助,将不胜感激。

所以总结一下我的pseudoIdea是这样的:

for each generation:
  if exit.flag != true:
    for each individual:
      evaluate individual
  else:
    write result
    finish and exit

when key detected set exit.flag to true

谢谢!

4

2 回答 2

0

虽然可以检测到按键,但您不必这样做。因为可以“捕获” Ctrl-c!

try:
    code_execution()
except KeyboardInterrupt:
    print("Ctrl-c was pressed, ready to exit")

KeyboardInterrupt基本上,按下 Ctrl-c 时会引发异常类型。这是您可以以任何您认为合适的方式捕捉和处理的东西。您可以在此处阅读有关此异常的更多信息,如果您不熟悉异常处理,是一个很好的起点。

奖励点 - 罕见的异常比 if 语句更快。

从您的评论中,我了解到您无法包装主要执行并阻止它停止,因此我包含了另一种方法。信号捕获。
Ctrl-c 发送进程 SIGINT ,我们可以将其配置为“陷阱”并以不同于正常(正在退出)的方式处理它。

import signal, os
import time

FLAG = False


def handler(signum, frame):
    """
    This function will execute each time Ctrl-c is pressed or SIGINT
    is sent to the process (such as `kill <pid>`).
    """
    global FLAG
    print('Signal handler called with signal', signum)
    FLAG = True

# Setup so we process signal SIGINT (includes Ctrl-C) with handler
signal.signal(signal.SIGINT, handler)


while True and not FLAG:
    time.sleep(0.5)
    print("Working hard!")
else:
    print("Done!")

您可以在他们的文档中阅读更多关于 Python 中的信号的信息。它也是一种标准的进程间通信方法,您可以使用它。

于 2020-05-02T08:14:04.020 回答
0

使用 pynput 找到了解决方案

from genetic.mainCore import Genetic
from grammar.basicDict import params
from algorithm.core import Algorithm
from pynput import keyboard


def on_activate_h():
    print('<ctrl>+<alt>+h pressed')
    global gen
    gen.forcEnd = True

listener = keyboard.GlobalHotKeys({'<ctrl>+<alt>+h': on_activate_h})
listener.start()

algi = Algorithm()
gen = Genetic(algi)
gen.initGrammar(params)
gen.initPopulation()
gen.run()

listener.stop()

我修改了 gen.run() 方法以包含一个 forcEnd 检查。如果它设置为 True 我们跳过下一代的评估并退出。对此进行了测试,即使使用外部模拟器也可以正常工作!

于 2020-05-02T10:52:30.680 回答