У меня есть список функций черного ящика (без обработки критических данных, без побочных эффектов от вызова, можно прекратить преждевременно), которые необходимо выполнить и их возвращаемые значения агрегированы:
aggregate = [result for fn in seq for result in fn()]
Функции обычно возвращаются в течение нескольких микросекунд, однако существуют крайние случаи, на которые я не могу повлиять, из-за которых некоторые из них иногда вызывают исключение, возвращают недопустимый тип (например, None
вместо итерируемого) или зависают бесконечно.
Чтобы обработать недопустимые выходные данные и исключения, я написал декоратор:
def safe_call(fn, valid_type, default, error_handler=None):
try:
val = fn()
if isinstance(val, valid_type):
return val
if error_handler is not None:
error_handler(TypeError("Invalid return type"))
except Exception as e:
if error_handler is not None:
error_handler(e)
return default
Теперь единственной проблемой являются зависания.Полное приведенное выше выражение должно всегда вычисляться в течение миллисекунд, и чтобы убедиться, что я пытаюсь реализовать тайм-аут 1 мс для каждой функции в последовательности.
Я пробовал многопоточность и многопроцессорность, но яне может должным образом завершить проблемные потоки, и издержки запуска нового процесса слишком высоки и сами по себе превышают значение тайм-аута в 1 миллисекунду.
Я пытался использовать сигналы, эталонный тест, указывающий на 25% накладных расходов на каждый вызов, что является приемлемым, но оценка выполняется с точки зрения django, который не запускается в главном потоке, поэтому сигналы не работают должным образом.
Мой текущий обходной путь - иметь отдельный процесс для каждой функции, постоянно синхронизирующийся с ее функцией.родительский процесс через очередь, ожидающий вызова.Таким образом, родитель может инициировать вызов по требованию, подождать 1 мс, а затем проверить, был ли результат отправлен обратно - сохранить результат, если он есть, или завершить процесс в противном случае.
Он работает в том, что касается производительности, но из-за этого решения накладные расходы памяти составляют 1400-1700%, что недопустимо.
Так, как мне тайм-аут вызова функции с помощью <Точность 1 мс без огромных накладных расходов памяти? </p>