Почему этот цикл Jython выходит из строя после одного прогона?
У меня есть следующий код:
public static String getVersion()
{
PythonInterpreter interpreter = new PythonInterpreter();
try
{
interpreter.exec(IOUtils.toString(new FileReader("./Application Documents/Scripts/Version.py")));
PyObject get_version = interpreter.get("get_latest_version");
PyObject result = get_version.__call__(interpreter.get("url"));
String latestVersion = (String) result.__tojava__(String.class);
interpreter.close();
return latestVersion;
} catch (IOException ex) {
ex.printStackTrace();
interpreter.close();
return Version.getLatestVersionOnSystem();
}
Для полноты я добавляю код Python:
import urllib2 as urllib
import warnings
url = 'arcticlights.ca/api/paint&requests?=version'
def get_latest_version(link=url):
request = urllib.Request(link)
handler = urllib.urllopen(request)
if handler.code is not 200:
warnings.warn('Invalid Status Code', RuntimeWarning)
return handler.read()
version = get_latest_version()
Он работает безупречно, но только в 10% случаев. Если я запустил его следующим образом:
public static void main(String[] args)
{
for (int i = 0; i < 10; i++) {
System.out.println(getVersion());
}
}
Он работает в первый раз. Он дает мне вывод, который я хочу, который является данными из HTTP-запроса, который написан в моем файле Versions.py
, который имеет код java выше вызовов. После второго раза он выдает эту массивную ошибку (длина которой составляет 950 строк, но, конечно, я не буду мучить вас, ребята). Вот его суть:
Aug 26, 2015 10:41:21 PM org.python.netty.util.concurrent.DefaultPromise execute
SEVERE: Failed to submit a listener notification task. Event loop shut down?
java.util.concurrent.RejectedExecutionException: event executor terminated
Трассировка My Python, которая поставляется в конце трассировки стека строк 950, в основном такова:
File "<string>", line 18, in get_latest_version
urllib2.URLError: <urlopen error [Errno -1] Unmapped exception: java.util.concurrent.RejectedExecutionException: event executor terminated>
Если кому-то интересно, кажущаяся оскорбительная строка в моем get_latest_version
справедлива:
handler = urllib2.urlopen(request)
Поскольку сервер, на котором выполняется вызов кода, запускается (через cherrypy) на localhost в моей сети, я вижу, как он взаимодействует с моим сервером. Он фактически отправляет два запроса (и выбрасывает исключение сразу после второго).
127.0.0.1 - - [26/Aug/2015:22:41:21] "GET / HTTP/1.1" 200 3 "" "Python-urllib/2.7"
127.0.0.1 - - [26/Aug/2015:22:41:21] "GET / HTTP/1.1" 200 3 "" "Python-urllib/2.7"
В то время как я никогда не буду запускать этот код в цикле, вероятно, мне очень интересно узнать о двух вещах:
- Является ли код нарушения моим кодом Python или Java? Или это может быть просто проблема с Jython?
- Что означает исключение (похоже, это исключение Java)? Почему его бросают, когда это происходит? Есть ли способ сделать цикл, подобный этой работе? Может ли это быть написано лучше?
Ответы
Ответ 1
В библиотеке python urllib2
, которую вы используете, используется Netty
.
Netty
имеет проблему, которая широко известна:
По всем этим ссылкам Netty
HttpClient
время от времени выходит из строя после закрытия. Похоже, что Netty
восстанавливается через некоторое время, и некоторые приложения работают нормально с этой проблемой. В любом случае, он выглядит неустойчивым.
Q: Является ли код нарушения моим кодом Python или Java? Или это может быть просто проблема с Jython?
A: Проблема вызвана библиотекой Jython urllib2
, которая использует Netty
.
Q: Что означает исключение (похоже, это исключение Java)? Почему он бросается, когда он есть?
A: urllib2
использует внутренне Netty
. Netty
написан на Java и выбрасывает это исключение Java. Netty
использует собственный Thread Executor, который отключается и неприменим в течение некоторого времени после закрытия запроса. Вы набрали именно это время.
Q: Есть ли способ сделать цикл таким образом? Может ли это быть написано лучше?
A: Я попытался бы использовать библиотеку Requests.
Ответ 2
Попробуйте дать интерпретатору свежее инициализированное состояние системы каждый раз, когда вы его создаете:
PySystemState.initialize();
PythonInterpreter interpreter = new PythonInterpreter(null, new PySystemState());