【问题标题】:Escaping arbitrary blocks of code转义任意代码块
【发布时间】:2012-06-29 23:07:56
【问题描述】:

我的脚本接受任意长度和内容的 Python 代码字符串,然后在 exec() 语句中运行它们。如果运行任意代码的时间超过了某个预定的限制,那么 exec() 语句需要退出,并且需要设置一个布尔标志来指示已经发生过早退出。

如何做到这一点?

附加信息

这些代码将在多个线程中并行运行(或至少与 GIL 一样并行)。

如果有其他语言的替代方法,我愿意尝试。

我计划清理代码以防止访问任何可能意外损坏我的系统的内容(文件和系统访问、导入语句、对 exec() 或 eval() 的嵌套调用等)。

我考虑过的选项

  1. 由于 exec() 语句在线程中运行,因此请使用毒丸杀死线程。不幸的是,我了解到毒丸并非对所有情况都有效。
  2. 在进程内运行 exec() 语句,然后使用process.terminate() 杀死所有内容。但是我在 Windows 上运行,并且我已经读过进程创建可能很昂贵。它还使与管理所有这些的代码的通信变得复杂。
  3. 只允许在 exec() 语句中预先编写函数,并让这些函数定期检查退出标志,然后根据需要执行清理。这既复杂又耗时,而且要考虑的极端情况太多;我正在寻找更简单的解决方案。

我知道这是一个有点奇怪的问题,值得提出“为什么要允许任意代码在 exec() 语句中运行?”响应类型。我正在尝试一些自我进化的代码。这是我目前的主要绊脚石:如果你允许你的代码做几乎任何事情,那么它可能会永远挂起。你如何重新获得控制权并在它发生时阻止它?

【问题讨论】:

  • 我建议在几乎没有权限的用户帐户下运行代码——仅足以运行代码。
  • 既然你在做自我进化的代码,那么对于“任意”的某种定义,它只是“任意”。这意味着您可能会完全放弃exec(),例如将代码包装在一个函数中。 exec() 确实允许您在一定程度上隔离代码,但您可以在进程中获得更好的隔离。我同意对你来说最好的解决方案可能是一个进程池,如果进程时间过长,进程管理器会终止进程。

标签: python python-3.x


【解决方案1】:

这不是一个非常详细的答案,但比我想发表的评论要多。

您可能需要考虑类似creating functions with timeouts, using multiprocessing 的其他问题作为开始。

线程的问题是您可能无法使用您的毒丸方法,因为它们不是执行许多小任务的工人。他们会坐在那里阻止发表声明。它永远不会获得退出的价值。

您提到您担心在 Windows 上使用进程是因为它们很昂贵。因此,您可能会创建自己的进程池(进程列表)。它们都从队列中拉出,您将新任务提交到队列中。如果有任何进程超过了超时时间,则将其杀死,并在池中将其替换为新进程。这样,您就可以将创建新进程的开销限制在它们超时时,而不是为每个任务创建一个新进程。

【讨论】:

  • 感谢您的回答。进程池是我的想法。
  • +1。但是在你做进程池之前,确保它对你的用例来说真的太贵了。您最终获得多少收益取决于您创建了多少进程,以及您必须多久杀死它们。此外,任务必须自行清理(如果它们没有被杀死),进程池才能工作。
【解决方案2】:

这里有几个不同的选项。

首先,从 jdi 的使用多处理的建议开始。可能是 Windows 进程创建实际上并不足以破坏您的用例。

如果这确实是个问题,我个人会使用 Virtual PC,甚至是用户模式 ​​Linux,只在另一个操作系统中运行相同的代码,而创建进程的成本很低。您还可以从中获得一个免费的沙盒。

如果您不想这样做,jdi 对进程池的建议是多一点工作,但只要您不必经常杀死进程,它应该可以正常工作。

如果您确实希望所有内容都成为线程,则可以这样做,只要您可以限制作业的编写方式。如果工作总是可以干净地展开,你可以通过引发异常来杀死它们。当然,他们也必须不捕获您选择引发的特定异常。显然,这些条件作为通用解决方案都不现实,但对于您的用例,它可能没问题。关键是要确保您的代码进化者永远不会插入任何手动资源管理语句(如打开和关闭文件);仅与语句。 (或者,插入打开和关闭,但在 try/finally 中。)即使您不以这种方式做事,这也可能是一个好主意,因为分离出数百个进程,例如,每个进程都会泄漏尽可能多的文件句柄因为他们可以,直到他们超时或达到文件限制会减慢您的机器爬行速度。

如果您可以进一步限制代码生成器/进化器,您可以使用某种形式的协作线程(例如 greenlets),这会使事情变得更好。

最后,您可以从 CPython 切换到可以在单个进程中运行多个解释器实例的不同 Python 实现。我不知道 jython 或 IronPython 是否可以这样做。 PyPy 可以做到这一点,并且还有一个受限环境沙箱,但不幸的是,我认为这两个——以及 Python 3.x 支持——都不是黄金时段的功能,这意味着你要么必须得到一个特殊的构建 PyPy(可能没有 JIT 优化器),或者自己构建。这可能是最好的长期解决方案,但可能不是您今天想要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多