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
miniyao
V2EX  ›  Python

怎么简单的限制一个函数的运行时间? try (in n seconds) 超时就 pass

  •  
  •   miniyao · 2020-10-03 13:56:33 +08:00 · 3558 次点击
    这是一个创建于 1532 天前的主题,其中的信息可能已经有所发展或是发生改变。

    由于在一个线程中接入了一个第三方服务,这个远程服务并不是很重要,远程调用线路和请求总有失败的可能。

    因此,就想把这个函数放在 Try 中去运行:

    try:
    
        do_something()
    
    except:
    
        pass
    

    由于每次 do_something() 会阻塞当前线程,所以想限制个最长执行时间,超时直接 pass 。

    用 eventlet 有点偏重,有没有什么比较简单的实现优雅的实现方法?

    14 条回复    2020-10-04 03:43:06 +08:00
    imn1
        1
    imn1  
       2020-10-03 13:58:23 +08:00
    远程模块一般都有 timeout 异常的
    Mitt
        2
    Mitt  
       2020-10-03 13:58:53 +08:00 via iPhone
    开线程超时然后强制终止?
    kangsheng9527
        3
    kangsheng9527  
       2020-10-03 13:59:27 +08:00
    python 不知道,go 可以使用 context 包去处理。。。
    JeffGe
        4
    JeffGe  
       2020-10-03 14:01:49 +08:00 via Android
    新建进程超时就 kill 可行吗
    dbow
        5
    dbow  
       2020-10-03 14:08:41 +08:00
    这种得用协程要搞, python3 里边有 async, await, 前提是你使用的库支持这么操作.
    infun
        6
    infun  
       2020-10-03 14:09:50 +08:00
    试试 retrying 库
    ClericPy
        7
    ClericPy  
       2020-10-03 14:30:37 +08:00
    线程差就差在没法外部强制停止, 所以这种场景我都是协程跑的, 外部超时直接发送 cancel 指令

    至于远程调用相关的, 一般会有超时控制吧, 具体看你 do 了什么 thing 了
    MoYi123
        8
    MoYi123  
       2020-10-03 14:37:27 +08:00   ❤️ 2
    @contextmanager
    def timeout_signal(second):
    ____signal.signal(signal.SIGALRM, raise_timeout)
    ____signal.alarm(second)
    ____try:
    ________yield
    ____finally:
    ________signal.signal(signal.SIGALRM, signal.SIG_IGN)


    def raise_timeout(_signum, _frame):
    ____raise TimeoutError


    def timeout(second):
    ____def _timeout(fun):
    ________@wraps(fun)
    ________def _fun(*args, **kwargs):
    ____________with timeout_signal(second):
    ________________return fun(*args, **kwargs)

    ________return _fun

    ____return _timeout


    @timeout(1)
    def f():
    ____pass


    我平时的用脚本里是这样写的,性能好坏不确定。
    MiracleKagari
        9
    MiracleKagari  
       2020-10-03 18:24:06 +08:00 via Android
    rxpy 应该有
    MiracleKagari
        10
    MiracleKagari  
       2020-10-03 20:12:02 +08:00 via Android
    @MiracleKagari 创建一个响应式对象,然后找一个合适的操作符,然后...
    tkmiles
        11
    tkmiles  
       2020-10-03 20:49:07 +08:00
    使用 future 呀
    一个线程结束之后更新 future
    另外一个线程在 future 上等待, future 上可以加 timeout 的
    然后另外一个线程在 timeout 之后直接终止子线程

    python 终止子线程有点限制, 只能发送线程异步异常去终止 python 代码执行, 如果你卡在 C 级别的代码, 那只能等待
    回调回 python 代码的时候, 异步异常才能终止线程

    如果你想终止线程更严格一点, 比如终止 C 代码, 那么只能求助于系统中断了
    itskingname
        12
    itskingname  
       2020-10-03 21:11:17 +08:00
    如果是 macOS 和 Linux,我写过一篇文章来说明: https://mp.weixin.qq.com/s/PUcHuJMG5Mk2tWWzYeq2wQ
    l4ever
        13
    l4ever  
       2020-10-04 02:33:47 +08:00 via iPhone
    import multiprocessing as mp
    def pool_funcs(func, args=(), kwds=None, timeout=1, default=None):
    """
    线程超时
    @param func:
    @param args:
    @param kwds:
    @param timeout:
    @param default:
    @return:
    """

    pool = mp.Pool(processes=1)
    result = pool.apply_async(func, args=args, kwds=kwds)
    try:
    val = result.get(timeout=timeout)
    except mp.TimeoutError:
    pool.terminate()
    return default
    else:
    pool.close()
    pool.join()
    return val
    namelosw
        14
    namelosw  
       2020-10-04 03:43:06 +08:00   ❤️ 1
    这个和停机问题相关,如果语言没有提供特殊的机制的话一般要靠子进程+监护的形式,因为停机是没法本地恢复的。像大量应用这种模式的 Erlang,也是尽量通过把进程做得超级轻量化,然后用同样的方式实现的。

    还有一些形式就是自己写一个简单的类似解释器的东西,你重新发明并嵌入一个语言,这个语言的解释归你管,就可以在每个求值周期都检查一次 timeout 。类似的例子比较像 React fiber —— 不过 fiber 只能管 React 渲染,而不能管 JavaScript 执行,也就是说这种 timeout 就 kill 掉的机制只能对 React 自己的 DSL ( JSX 以及 Element 的 Rendering )成立,而对 JavaScript 没有普适性,除非重新实现一遍 JavaScript,或者启另外一个 JavaScript 进程。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2880 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 10:43 · PVG 18:43 · LAX 02:43 · JFK 05:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.