과거에는 파이썬에서 시간 제한 기능을 추가하여 지정된 제한 시간이 만료되면 대기 코드가 계속 움직일 수있는 시도가 많이있었습니다. 불행하게도, 이전의 방법은 실행중인 함수가 계속 실행되고 리소스를 소비하거나 플랫폼에 특정한 스레드 종료 방법을 사용하여 함수를 종료 할 수있었습니다. 이 위키의 목적은 많은 프로그래머가 다양한 프로그래밍 프로젝트를 수행해야했던이 문제에 대한 크로스 플랫폼 응답을 개발하는 것입니다. 파이썬에서 함수에 타임 아웃을 추가하는 방법
#! /usr/bin/env python
"""Provide way to add timeout specifications to arbitrary functions.
There are many ways to add a timeout to a function, but no solution
is both cross-platform and capable of terminating the procedure. This
module use the multiprocessing module to solve both of those problems."""
################################################################################
__author__ = 'Stephen "Zero" Chappell <[email protected]>'
__date__ = '11 February 2010'
__version__ = '$Revision: 3 $'
################################################################################
import inspect
import sys
import time
import multiprocessing
################################################################################
def add_timeout(function, limit=60):
"""Add a timeout parameter to a function and return it.
It is illegal to pass anything other than a function as the first
parameter. If the limit is not given, it gets a default value equal
to one minute. The function is wrapped and returned to the caller."""
assert inspect.isfunction(function)
if limit <= 0:
raise ValueError()
return _Timeout(function, limit)
class NotReadyError(Exception): pass
################################################################################
def _target(queue, function, *args, **kwargs):
"""Run a function with arguments and return output via a queue.
This is a helper function for the Process created in _Timeout. It runs
the function with positional arguments and keyword arguments and then
returns the function's output by way of a queue. If an exception gets
raised, it is returned to _Timeout to be raised by the value property."""
try:
queue.put((True, function(*args, **kwargs)))
except:
queue.put((False, sys.exc_info()[1]))
class _Timeout:
"""Wrap a function and add a timeout (limit) attribute to it.
Instances of this class are automatically generated by the add_timeout
function defined above. Wrapping a function allows asynchronous calls
to be made and termination of execution after a timeout has passed."""
def __init__(self, function, limit):
"""Initialize instance in preparation for being called."""
self.__limit = limit
self.__function = function
self.__timeout = time.clock()
self.__process = multiprocessing.Process()
self.__queue = multiprocessing.Queue()
def __call__(self, *args, **kwargs):
"""Execute the embedded function object asynchronously.
The function given to the constructor is transparently called and
requires that "ready" be intermittently polled. If and when it is
True, the "value" property may then be checked for returned data."""
self.cancel()
self.__queue = multiprocessing.Queue(1)
args = (self.__queue, self.__function) + args
self.__process = multiprocessing.Process(target=_target,
args=args,
kwargs=kwargs)
self.__process.daemon = True
self.__process.start()
self.__timeout = self.__limit + time.clock()
def cancel(self):
"""Terminate any possible execution of the embedded function."""
if self.__process.is_alive():
self.__process.terminate()
@property
def ready(self):
"""Read-only property indicating status of "value" property."""
if self.__queue.full():
return True
elif not self.__queue.empty():
return True
elif self.__timeout < time.clock():
self.cancel()
else:
return False
@property
def value(self):
"""Read-only property containing data returned from function."""
if self.ready is True:
flag, load = self.__queue.get()
if flag:
return load
raise load
raise NotReadyError()
def __get_limit(self):
return self.__limit
def __set_limit(self, value):
if value <= 0:
raise ValueError()
self.__limit = value
limit = property(__get_limit, __set_limit,
doc="Property for controlling the value of the timeout.")
편집 :이 코드는 파이썬 3.x를 위해 작성되었으며 장식으로 클래스 메소드를 위해 설계되지 않았습니다. multiprocessing
모듈은 프로세스 경계에서 클래스 인스턴스를 수정하도록 설계되지 않았습니다.
예외 처리는 Python 3에서만 작동합니다.x는 원래 스택 트레이스를 버리고 "raise"에서 시작된 것으로 예외를 표시하며 스택 트레이스에는 어설 션이 전혀 표시되지 않습니다. –