2

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

如何实现?

附加信息

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

如果有另一种语言的替代方法,我愿意尝试一下。

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

我考虑过的选项

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

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

4

2 回答 2

3

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

您可能需要考虑类似其他问题的问题,以使用多处理作为开始 来创建具有超时的函数。

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

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

于 2012-06-29T23:27:10.480 回答
3

这里有几个不同的选项。

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

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

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

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

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

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

于 2012-06-30T01:09:35.337 回答