有什么好办法约束一个函数的执行时间吗?

2017-08-14 19:28:11 +08:00
 petelin

自己搜到的几个方法都有缺陷:

  1. signal: 如果方法运行在一个子线程中, 是不能接受信号的.
  2. 多线程: 开一个子线程执行, python 没有办法直接杀掉子线程.
  3. 开一个子进程, 设置为 daemon, 然后主进程退出他也会退出, 如果函数本身执行在 daemon 线程中, 是不能新建进程的.

我在想 fork 一个独立的进程, 然后发送 kill 信号, 这样会不会有问题, 另外如何得到 fork 出来的线程的输出呢?好像没有 Queue 这种东西可以用了.

3286 次点击
所在节点    Python
15 条回复
petelin
2017-08-14 19:38:51 +08:00
创建主题时描述错了,为看到的 v 友说声抱歉, Process 和 Thread 说的乱七八糟的, 已改正.
Victor215
2017-08-14 19:47:29 +08:00
docker
zeq
2017-08-14 23:56:28 +08:00
celery 🙈
shawlib
2017-08-15 00:12:38 +08:00
shawlib
2017-08-15 00:13:53 +08:00
老哥,找到什么好方法了公布下
misaka19000
2017-08-15 00:22:06 +08:00
创建一个进程之后获取到 pid,时间到了直接 kill
neoblackcap
2017-08-15 00:26:56 +08:00
你是要开发实时系统吗?楼主你说的都是软实时的,简单来说,内核对你的进程进行调度,那么你的函数执行时间上限就有可能会超过了。真要硬实时的话我还是建议你用 C,然后老实地独占一个核心。
HarveyDent
2017-08-15 08:36:55 +08:00
不知道是不是想要这种:把函数内的执行代码分成小块,然后每一小块执行完后检查执行时间,超时既返回。如果执行自己写的函数,可以用这种方法。
petelin
2017-08-15 13:54:29 +08:00
@HarveyDent 比如有一句 sleep(10), 这句话没法再被拆分了.
petelin
2017-08-15 14:43:00 +08:00
```
def run_with_limited_time(func, args, kwargs, time):
"""Runs a function with time limit
:param func: The function to run
:param args: The functions args, given as tuple
:param kwargs: The functions keywords, given as dict
:param time: The time limit in seconds
:return: True if the function ended successfully. False if it was terminated.
"""
def wrapper(queue, func, *args, **kwargs):
return queue.put(func(*args, **kwargs))
import multiprocessing
q = multiprocessing.Queue(maxsize=1)
func = functools.partial(wrapper, q, func)
p = Process(target=func, args=args, kwargs=kwargs)
p.start()
p.join(time)
if p.is_alive():
p.terminate()
raise TimeoutError('time out!')

return q.get_nowait()
```

看起来是最好的实现了
lolizeppelin
2017-08-15 23:29:14 +08:00
循环里设置标记位置,循环外部能控制这个标记位置让循环退出
petelin
2017-08-16 15:23:49 +08:00
@lolizeppelin 不行。
lolizeppelin
2017-08-17 08:39:50 +08:00
sleep 可以同信号抛出异常的
lolizeppelin
2017-08-17 08:45:22 +08:00
哦 重新看了下你说的

用 eventlet 写协程可以做到
因为里面没有真正的 sleep
sleep 都被 hack 成排序调度的位置了

协程本身可以终止
shawlib
2017-08-18 17:43:00 +08:00
# 超时装饰器
import signal,functools # 下面会用到的两个库
class TimeoutError(Exception): pass # 定义一个 Exception,后面超时抛出

def timeout(seconds, error_message = 'Function call timed out'):
def decorated(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return functools.wraps(func)(wrapper)
return decorated

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/382881

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX