简体   繁体   English

timeit内的Python函数调用超时

[英]Timeout on a Python function call inside timeit

I have a function, let's call it my_function(*args, **kwargs) , that depending on the arguments passed to it takes anywhere from 30 seconds to many many hours (days). 我有一个函数,我们称它为my_function(*args, **kwargs) ,根据传递给它的参数的不同,它花费的时间从30秒到很多小时(几天)不等。 I have a list of different arguments and I want to know how long the functions will take given the arguments. 我有一个不同参数的列表,我想知道给定参数这些函数将花费多长时间。

I am still very new to using timeit , but I have learn enough to do this part; 我对使用timeit还是很timeit ,但是我已经学到了足够的知识来完成这一部分。 however, this wouldn't be the very efficient for my purposes. 但是,对于我的目的而言,这并不是非常有效。 Any set of arguments that take longer than 4 hours to complete are consider intractable, despite all of them being able to be solved in "finite" time. 尽管所有参数都可以在“有限的”时间内解决,但是所有花费超过4个小时才能完成的参数都被认为是棘手的。 As some (possibly most) of the arguments will results in run times that will take upwards of 20+ hours, I am looking for a way to terminate a test after 4 hours so that I don't have to waste time after figuring out that it is intractable. 由于某些参数(可能是大多数参数)会导致运行时间长达20多个小时,因此我正在寻找一种方法,可以在4小时后终止测试,这样我就不必在弄明白这很棘手。

I have looked at Timeout on a Python function call and Stop code after time period , and this might be close enough of a question to be a duplicate, but I am having trouble integrating those answers with timeit so that times less that 4 hours are recorded like they should be while long runs return some valid time greater than 4 hours. 我查看了一段时间后 的Python函数调用Stop代码 上的Timeout ,这可能是一个足够接近的问题,可以重复,但是我无法将这些答案与timeit集成在一起,因此记录的时间少于4小时就像他们应该在长期运行时返回一些大于4小时的有效时间一样。

What would be the best way to go about doing this? 这样做的最佳方法是什么?

EDIT : One of the problems that I have had with it is that the answers that I've seen have take in func(*args,**kwargs) while the timeit functions looks like this: 编辑:我遇到的问题之一是,我看到的答案已经包含在func(*args,**kwargs)timeit函数看起来像这样:

timeit.Timer('my_function(*args, **kwargs)', setup=setup).timeit(1)

I don't know how to handle this form. 我不知道如何处理此表格。

EDIT : The original answer that I provided below using threads doesn't actually terminate the threads. 编辑:我下面使用线程提供的原始答案实际上并不终止线程。 This can easily be shown by running it with the following function. 通过使用以下功能运行它可以很容易地显示出来。

def foo(x):
    for i in xrange(1, x + 1):
        sleep(1)
        print i
    return x

Using a code that involves multiprocessing.Pool , which actually has a terminate() , allow for this. 使用涉及multiprocessing.Pool的代码terminate()实际上有一个terminate()允许这样做。

Based on the answer found in Timeout function using threading in python does not work . 基于超时功能中找到的答案, 在python中使用线程不起作用 If you try it out on foo(x) it does indeed stop counting unlike the my previous answer. 如果您在foo(x)上进行尝试,它的确会停止计数,这与我之前的回答不同。

import multiprocessing as mp
import timeit

def timeout(func, args=(), kwargs=None, TIMEOUT=10, default=None, err=.05):

    if hasattr(args, "__iter__") and not isinstance(args, basestring):
        args = args
    else:
        args = [args]    
    kwargs = {} if kwargs is None else kwargs

    pool = mp.Pool(processes = 1)

    try:
        result = pool.apply_async(func, args=args, kwds=kwargs)
        val = result.get(timeout = TIMEOUT * (1 + err))
    except mp.TimeoutError:
        pool.terminate()
        return default
    else:
        pool.close()
        pool.join()
        return val

def Timeit(command, setup=''):
    return timeit.Timer(command, setup=setup).timeit(1)

def timeit_timeout(command, setup='', TIMEOUT=10, default=None, err=.05):
    return timeout(Timeit, args=command, kwargs={'setup':setup},
                   TIMEOUT=TIMEOUT, default=default, err=err) 

After some more fiddling I have a initial answer based on Timeout function using threading . 经过一番摆弄之后,我有了一个基于Timeout函数的使用线程的初步答案。 I would still love to hear from anyone who has better ideas as I am still new to this. 我仍然很乐意收到任何有更好想法的人的来信,因为我还是这个新手。

def timeout(func, args=None, kwargs=None, TIMEOUT=10, default=None, err=.05):
    if args is None:
        args = []
    elif hasattr(args, "__iter__") and not isinstance(args, basestring):
        args = args
    else:
        args = [args]

    kwargs = {} if kwargs is None else kwargs

    import threading
    class InterruptableThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.result = None

        def run(self):
            try:
                self.result = func(*args, **kwargs)
            except:
                self.result = default

    it = InterruptableThread()
    it.start()
    it.join(TIMEOUT* (1 + err))
    if it.isAlive():
        return default
    else:
        return it.result

def timeit_timeout(command, setup='', TIMEOUT=10, default=None, err=.05):
    import timeit
    f = lambda: timeit.Timer(command, setup=setup).timeit(1)
    return timeout(f,TIMEOUT=TIMEOUT, default=default, err=err) 

if __name__ == '__main__':    
    from time import sleep
    setup = 'gc.enable()\nfrom time import sleep'
    for n in range(1,15):
        command = 'sleep({})'.format(n)
        print timeit_timeout(command, setup=setup, default=float('Inf'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM