如何限制函数运行的时间(添加超时)?

时间:2017-04-11 02:57:50

标签: python linux timer timeout scheduling

如何设置函数运行的最长时间限制? 例如,使用time.sleep作为占位符函数,如何将时间time.sleep限制为最多可以运行5分钟(300秒)?

import time

try:
    # As noted above `time.sleep` is a placeholder for a function 
    # which takes 10 minutes to complete.
    time.sleep(600)
except:
    print('took too long')

也就是说,300秒后如何限制和中断time.sleep(600)以上?

2 个答案:

答案 0 :(得分:3)

在POSIX上,您可以在signal模块中使用简单而干净的解决方案。

function StackOverflow
close all
set(groot,'defaultLineLineWidth',3)

dx=pi/100;
x = (0:dx:2*pi)';
N = length(x);

Y = nan(size(x,1),2);
Y(1,:) = [1, 0];

F = { @(x,y)  y(2) , @(x,y) -y(1) };

for i=1:N-1                              % calculation loop
    k_1 = cellfun(@(f) f(x(i)         , Y(i,:))              , F);
    k_2 = cellfun(@(f) f(x(i) + 0.5*dx, Y(i,:) + 0.5*dx*k_1) , F);
    k_3 = cellfun(@(f) f(x(i) + 0.5*dx, Y(i,:) + 0.5*dx*k_2) , F);
    k_4 = cellfun(@(f) f(x(i) +     dx, Y(i,:) +     dx*k_3) , F);

    Y(i+1,:) = Y(i,:) + (dx/6)*(k_1+2*k_2+2*k_3+k_4);  % main equation
end

y = Y(:,1);
u = Y(:,2);

figure(1)
set(gcf, 'units', 'normalized')

subplot(2,1,1)
plot(x , y , '--', x, cos(x), ':')
axis('tight')
set(gca,'fontsize',14, 'Position',[0.12 0.55 0.84 0.4])
xticks(0:pi/2:2*pi)
xticklabels({})
ylabel('$y(x)=\cos(x)$', 'Interpreter', 'latex')


subplot(2,1,2)
plot(x , u, '--', x, -sin(x), ':')
set(gca,'fontsize',14, 'Position',[0.12 0.1 0.84 0.4])
axis('tight')
xticks(0:pi/2:2*pi)
xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi'})

xlabel('x', 'Interpreter', 'latex')
ylabel('$y''(x)=-\sin(x)$', 'Interpreter', 'latex')

end

警告:

  • 不适用于所有平台,例如视窗。
  • 在线程应用程序中不起作用,只在主线程中起作用。

对于上述警告是破坏交易的其他读者,您需要更重量级的方法。最好的选择通常是在单独的进程(或可能是线程)中运行代码,如果花费的时间太长,则终止该进程。例如,请参阅multiprocessing模块。

答案 1 :(得分:2)

当前可能首选的选项之一就是使用Pythons

  

多处理(尤其是 proc.join(timeoutTime)方法)

模块(见tutorial

只需复制/粘贴下面的代码示例并运行它即可。这是你的追求吗?

def beBusyFor(noOfSeconds):
    import time
    print("    beBusyFor() message: going to rest for", noOfSeconds, "seconds")
    time.sleep(noOfSeconds)
    print("    beBusyFor() message: was resting", noOfSeconds, "seconds, now AWAKE")

import multiprocessing

noOfSecondsBusy = 5; timeoutTime  = 3
print("--- noOfSecondsBusy = 5; timeoutTime  = 3 ---")
proc = multiprocessing.Process(target=beBusyFor, args=(noOfSecondsBusy, ))
print("Start beBusyFor()")
proc.start()
print("beBusyFor() is running")
proc.join(timeoutTime)
if proc.is_alive():
    print(timeoutTime, "seconds passed, beBusyFor() still running, terminate()" )
    proc.terminate()
else:
    print("OK, beBusyFor() has finished its work in time.")
#:if    

print()

noOfSecondsBusy = 2; timeoutTime  = 3
print("--- noOfSecondsBusy = 2; timeoutTime  = 3 ---")
proc = multiprocessing.Process(target=beBusyFor, args=(noOfSecondsBusy, ))
print("Start beBusyFor()")
proc.start()
print("beBusyFor() started")
proc.join(timeoutTime)
if proc.is_alive():
    print(timeoutTime, "seconds passed, beBusyFor() still running, terminate()" )
    proc.terminate()
else:
    print("OK, beBusyFor() has finished its work in time.")
#:if    

输出:

--- noOfSecondsBusy = 5; timeoutTime  = 3 ---
Start beBusyFor()
beBusyFor() is running
    beBusyFor() message: going to rest for 5 seconds
3 seconds passed, beBusyFor() still running, terminate()

--- noOfSecondsBusy = 2; timeoutTime  = 3 ---
Start beBusyFor()
beBusyFor() started
    beBusyFor() message: going to rest for 2 seconds
    beBusyFor() message: was resting 2 seconds, now AWAKE
OK, beBusyFor() has finished its work in time.

我所知道的另一个选择是使用

  

装饰器功能信号模块

查看我在此处提供的web page with origin of the code(只需要进行一次小调整即可在Python 3.6上运行):

import signal

class TimeoutError(Exception):
    def __init__(self, value = "Timed Out"):
        self.value = value
    def __str__(self):
        return repr(self.value)

def timeout(seconds_before_timeout):
    def decorate(f):
        def handler(signum, frame):
            raise TimeoutError()
        def new_f(*args, **kwargs):
            old = signal.signal(signal.SIGALRM, handler)
            signal.alarm(seconds_before_timeout)
            try:
                result = f(*args, **kwargs)
            finally:
                signal.signal(signal.SIGALRM, old)
            signal.alarm(0)
            return result
        # new_f.func_name = f.func_name
        new_f.__name__ = f.__name__
        return new_f
    return decorate

# Try it out:

import time

@timeout(5)
def mytest():
    print( "mytest() message:  Started" )
    for i in range(1,10):
        time.sleep(1)
        print( "mytest() message:  %d seconds have passed" % i )

try:
    mytest()
except TimeoutError as e:
    print("stopped executing mytest() because it", e)

print("continuing script execution past call of mytest()")

上面的代码输出:

mytest() message:  Started
mytest() message:  1 seconds have passed
mytest() message:  2 seconds have passed
mytest() message:  3 seconds have passed
mytest() message:  4 seconds have passed
stopped executing mytest() because it 'Timed Out'
continuing script execution past call of mytest()