Python:统计方法调用时间并在超时后停止

3 投票
7 回答
2966 浏览
提问于 2025-04-15 14:35

我需要动态加载代码(以源代码的形式),运行它并获取结果。加载的代码总是包含一个运行方法,这个方法会返回所需的结果。看起来一切都非常简单,就像在Python中一样,因为我可以这样做:

exec(source) #source includes run() definition
result = run(params)
#do stuff with result

唯一的问题是,动态生成的代码中的run()方法可能不会结束,所以我需要限制它的运行时间,最多运行x秒。我可以为此创建一个新线程,并为.join()方法指定一个时间,但这样我就不容易从中获取结果了(或者我可以吗)。性能也是一个需要考虑的问题,因为这一切都发生在一个很长的循环中。

有没有什么建议可以帮助我解决这个问题?

补充说明:为了澄清dcrosta的请求:加载的代码是可信的,但在机器上自动生成的。这样做的目的是为了进行遗传编程。

7 个回答

2

你可以使用 multiprocessing 这个库来在一个单独的进程中运行代码,并通过调用 .join() 来等待这个进程完成,你可以设置一个超时时间,随便你想要多长。这个库提供了几种方法来从另一个进程获取数据——使用一个 Value 对象(在那个页面的共享内存示例中可以看到)可能就足够了。如果你真的需要的话,可以对进程使用 terminate() 来强制结束,不过这并不是推荐的做法。

2

你也可以使用无栈的Python,因为它支持微线程的协作调度。这样你可以设定在返回之前最多执行多少条指令。不过,设置这些例程和获取返回值会稍微复杂一些。

5

唯一“真的不错”的解决方案几乎没有额外负担,都是基于SIGALRM的,要么直接使用,要么通过一个很好的抽象层来实现;但正如之前提到的,Windows不支持这个。线程在这里没什么用,不是因为获取结果很难(这其实很简单,用队列就行!),而是因为强行终止一个失控的线程在跨平台上是不可行的。

这就只剩下高开销的multiprocessing作为唯一可行的跨平台解决方案。你会想要一个进程池来减少创建进程的开销(因为通常情况下,杀掉一个失控的函数是偶尔需要的,大部分时间你可以通过发送新函数给现有的进程来重用它)。同样,队列(多进程的那种)让获取结果变得简单(虽然比线程的情况需要多一点小心,因为在多进程的情况下可能会出现死锁)。

如果你不需要严格按照顺序执行你的函数,而是可以安排架构让两个或更多的函数并行运行,并且你是在一个多核机器上(或者在快速局域网中的多台机器上),那么多进程就突然变成了一个高性能的解决方案,轻松弥补了创建进程和进程间通信的开销,甚至更多,因为你可以充分利用尽可能多的处理器(或者集群中的节点)。

撰写回答