V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
petelin
V2EX  ›  Python

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

  •  
  •   petelin · 2017-08-14 19:28:11 +08:00 · 3397 次点击
    这是一个创建于 2665 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    15 条回复    2017-08-18 17:43:00 +08:00
    petelin
        1
    petelin  
    OP
       2017-08-14 19:38:51 +08:00
    创建主题时描述错了,为看到的 v 友说声抱歉, Process 和 Thread 说的乱七八糟的, 已改正.
    Victor215
        2
    Victor215  
       2017-08-14 19:47:29 +08:00 via Android
    docker
    zeq
        3
    zeq  
       2017-08-14 23:56:28 +08:00 via iPhone
    celery 🙈
    shawlib
        4
    shawlib  
       2017-08-15 00:12:38 +08:00
    shawlib
        5
    shawlib  
       2017-08-15 00:13:53 +08:00
    老哥,找到什么好方法了公布下
    misaka19000
        6
    misaka19000  
       2017-08-15 00:22:06 +08:00
    创建一个进程之后获取到 pid,时间到了直接 kill
    neoblackcap
        7
    neoblackcap  
       2017-08-15 00:26:56 +08:00
    你是要开发实时系统吗?楼主你说的都是软实时的,简单来说,内核对你的进程进行调度,那么你的函数执行时间上限就有可能会超过了。真要硬实时的话我还是建议你用 C,然后老实地独占一个核心。
    HarveyDent
        8
    HarveyDent  
       2017-08-15 08:36:55 +08:00
    不知道是不是想要这种:把函数内的执行代码分成小块,然后每一小块执行完后检查执行时间,超时既返回。如果执行自己写的函数,可以用这种方法。
    petelin
        9
    petelin  
    OP
       2017-08-15 13:54:29 +08:00
    @HarveyDent 比如有一句 sleep(10), 这句话没法再被拆分了.
    petelin
        10
    petelin  
    OP
       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
        11
    lolizeppelin  
       2017-08-15 23:29:14 +08:00
    循环里设置标记位置,循环外部能控制这个标记位置让循环退出
    petelin
        12
    petelin  
    OP
       2017-08-16 15:23:49 +08:00
    @lolizeppelin 不行。
    lolizeppelin
        13
    lolizeppelin  
       2017-08-17 08:39:50 +08:00 via Android
    sleep 可以同信号抛出异常的
    lolizeppelin
        14
    lolizeppelin  
       2017-08-17 08:45:22 +08:00 via Android
    哦 重新看了下你说的

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

    协程本身可以终止
    shawlib
        15
    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
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1840 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:24 · PVG 00:24 · LAX 08:24 · JFK 11:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.