Когда использовать cleanup() в Jython

#java #jython #scripting-language #jython-2.7

#java #jython #язык сценариев #jython-2.7

Вопрос:

Обязательно ли каждый раз вызывать cleanup() before close() в PythonInterpreter в Jython?

Я читал документы, но не нашел много информации об этой функции. javadocs вообще ничего не говорят. Самая близкая информация, которую я нашел, находится здесь, в readthedocs , где они объясняют, что очистка необходима в некоторых случаях программирования с использованием потоков, и я даже не уверен, что они ссылаются на эту конкретную функцию.

Интересно, когда мне нужно позвонить cleanup() … и если ответ всегда, то зачем им создавать cleanup() и close() отдельные функции?

Комментарии:

1. На самом деле у меня нет ответа, но cleanup() вызывается из close() . Смотрите github.com/jython/jython/blob/master/src/org/python/util /… .

2. Что ж, для меня этого достаточно. Спасибо!

Ответ №1:

Хорошо, я прочитал исходный код Jython и выполнил несколько тестов. Вот что я нашел:

Что cleanup() делает: Он берет на себя ответственность за необработанные ресурсы, такие как запущенные потоки и файлы.

Что cleanup() не делает: Сбрасывает состояние интерпретатора в любой форме; импортированные модули и определенные переменные сохраняются.

Следующие примеры демонстрируют это поведение:

Пример 1

Давайте импортируем модуль, определим переменную и откроем файл.

 PythonInterpreter py = new PythonInterpreter();

String code1 = "import sys;"
          "a=45;"
          "f = open('test.txt')";
String code2 = "print(sys.version_info);"
          "print(a);"
          "print(f.closed)";

// first execution
py.exec(code1);
py.exec(code2);

// second execution
py.cleanup();
py.exec(code2);

py.close()
  

Он выводит

 sys.version_info(major=2, minor=7, micro=2, releaselevel='final', serial=0)
45
False
------
sys.version_info(major=2, minor=7, micro=2, releaselevel='final', serial=0)
45
True
  

Модуль sys и переменные a и f все еще существуют с теми же значениями после очистки, но открытый файл закрыт.

Пример 2

Для этого func используется медленная функция, выполнение которой занимает примерно 2 секунды (больше, чем обычно cleanup() ).

 PythonInterpreter py = new PythonInterpreter();

String code3 = "from threading import Threadn"
          "def func():n"
          "  print 'th start'n"
          "  for i in range(0,20000000):n"
          "    x=in"
          "  print 'th done'n"
          "th = Thread(target=func)n"
          "th.start()";
String code4 = "print th.isAlive()n"
          "th.join()";

// first execution
py.exec(code3);
py.exec(code4);
System.out.println("------");   

// second execution
py.exec(code3);
py.cleanup();
py.exec(code4);

py.close();
  

Это выводит:

 th start
True
th done
------
th start
th done
False
  

При первом выполнении у основного потока есть достаточно времени, чтобы проверить, работает ли th , и распечатать его. Во втором он всегда ожидает th завершения, что означает, что cleanup() где-то присоединяется к потоку.

Заключение

Как указал @mzjn, close() функция вызывает cleanup() , и это имеет смысл, поэтому вам никогда не нужно вызывать cleanup() раньше close() . Единственный случай, когда вам может понадобиться вызвать его вручную, это если вы хотите продолжить использовать PythonInterpreter , но вам необходимо закрыть все открытые файлы и присоединиться ко всем потокам.

Комментарии:

1. Спасибо за подробную информацию. Что, если у меня есть интерпретатор, прослушивающий все поступающие запросы interpreter.exec() или interpreter.eval() ? Нужно ли мне периодически вызывать вручную cleanup() ? Я провожу нагрузочный тест, где я вижу, что для того же кода Python время выполнения становится все медленнее и медленнее. И через некоторое время время выполнения становится лучше, а затем снова медленнее. Но я вижу, что общее время выполнения становится больше. Я думаю, cleanup() может помочь или нет?

2. Насколько я понимаю, если вы правильно управляете файлами и потоками в своем коде (закрываете и объединяете их соответственно), в этом не было бы необходимости.

3. Я не управляю файлами, а просто инициализирую экземпляр и вызываю метод. Насколько я понимаю, основываясь на документе Jython, я могу напрямую использовать собственное управление потоками интерпретатора для обработки поступающего вызова eval or exec (поскольку интерпретатор потокобезопасен): у меня есть пул для контроля того, сколько запросов обрабатывается в данный момент, но все они используют один и тот же интерпретатор. Прежде чем вы ответили, я пытался периодически вызывать cleanup() , и, похоже, потребление памяти более стабильно, а время выполнения также более стабильно. Но мне может понадобиться дополнительный нагрузочный тест, чтобы увидеть, действительно ли это помогает.

4. @Vision ты нашел решение для своего, я вижу то же самое