如何以python方式检查长时间运行的函数?

Ale*_*eev 11 python pickle checkpointing

计算科学中的典型情况是有一个连续运行数天/数周/数月的程序。由于硬件/操作系统故障是不可避免的,因此通常使用检查点,即不时保存程序的状态。如果失败,则从最新的检查点重新启动。

实现检查点的pythonic方法是什么?

例如,可以直接转储函数的变量。

或者,我正在考虑将此类函数转换为一个类(见下文)。函数的参数将成为构造函数的参数。构成算法状态的中间数据将成为类属性。和pickle模块将帮助(缩小)序列化。

import pickle

# The file with checkpointing data
chkpt_fname = 'pickle.checkpoint'

class Factorial:
    def __init__(self, n):
        # Arguments of the algorithm
        self.n = n

        # Intermediate data (state of the algorithm)
        self.prod = 1
        self.begin = 0

    def get(self, need_restart):
        # Last time the function crashed. Need to restore the state.
        if need_restart:
            with open(chkpt_fname, 'rb') as f:
                self = pickle.load(f)

        for i in range(self.begin, self.n):
            # Some computations
            self.prod *= (i + 1)
            self.begin = i + 1

            # Some part of the computations is completed. Save the state.
            with open(chkpt_fname, 'wb') as f:
                pickle.dump(self, f)

            # Artificial failure of the hardware/OS/Ctrl-C/etc.
            if (not need_restart) and (i == 3):
                return

        return self.prod


if __name__ == '__main__':
    f = Factorial(6)
    print(f.get(need_restart=False))
    print(f.get(need_restart=True))
Run Code Online (Sandbox Code Playgroud)

awi*_*ebe 4

通常答案是使用您最喜欢的序列化方法进行序列化,即 cpickle json 或 xml。Pickle 的优点是您可以反序列化整个对象,而无需太多额外的工作。

此外,将进程与状态分开是个好主意,因此您只需序列化状态对象即可。许多对象无法被 pickle,例如线程,但您可能想要运行许多工作线程(尽管要注意 GIL),因此 pickle 会在您尝试 pickle 它们时抛出异常。您可以通过删除导致问题的条目来解决此_getstate_问题_setstate_ - 但如果您只是将流程和状态分开,这将不再是问题。

要进行检查点,请将检查点文件保存到已知位置,当程序启动时,检查该文件是否存在,如果不存在则进程尚未启动,否则加载并运行它。创建一个线程,通过清空任何工作线程正在处理的队列,然后保存状态对象,定期对正在运行的任务进行检查点,然后重用您使用的恢复逻辑,以防在检查点后恢复。

为了安全地检查点,您需要确保您的程序不会因在 pickle 中死亡而损坏检查点文件。去做这个

  1. 在临时位置创建检查点并完成写入
  2. 将最后一个检查点重命名为checkpoint.old
  3. 将新检查点重命名为checkpoint.pickle
  4. 消除checkpoint.old
  5. 如果启动程序并且没有检查点但有checkpoint.old,则程序在步骤 2 后死亡,因此加载checkpoint.old,重命名checkpoint.oldcheckpoint.pickle并正常运行。如果程序在其他地方死掉了,您只需重新加载即可checkpoint.pickle