为什么这个 Jython 循环在单个 运行 后失败?

Why does this Jython loop fail after a single run?

我有以下代码:

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());
    }   
}

第一次成功。它给了我我想要的输出,这是写在我的 Versions.py 文件中的 http 请求的数据,上面的 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

我的 Python 在 950 行 Java 堆栈跟踪末尾提供的回溯主要是这样的:

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)在我网络的本地主机上,我可以看到它是如何与我的服务器交互的。它实际上发送了两个请求(并在第二个之后立即抛出异常)。

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 库 urllib2 使用 Netty.

Netty有个问题,广为人知:

根据所有这些链接 Netty HttpClient 关闭后有时会失败。看起来 Netty 会在一段时间后恢复,并且一些应用程序可以正常运行这个问题。反正看起来不稳定


问:违规代码是我的 Python 还是 Java 代码?还是完全是 Jython 的问题?

答:问题是由 Jython 库 urllib2 引起的,它使用了 Netty.


问:异常是什么意思(看起来像java异常)?为什么它被抛出?

答:urllib2 内部使用 NettyNetty写在Java里面,抛出这个Java异常。 Netty 使用自己的Thread Executor,在关闭一个请求后,会在一段时间内关闭并且无法使用。这次你正好击中了。


问:有没有办法让这样的循环工作?这个能写的更好吗?

答:我会尝试使用 Requests 库。

尝试在每次创建解释器时为其提供一个全新初始化的系统状态:

PySystemState.initialize();
PythonInterpreter interpreter = new PythonInterpreter(null, new PySystemState());