2015-08-27 14 views
15

ich den folgenden Code haben:Warum schlägt diese Jython-Schleife nach einem einzigen Durchlauf fehl?

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

Aus Gründen der Vollständigkeit, ich bin der Python-Code hinzufügen:

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

Es funktioniert einwandfrei, aber nur 10% der Zeit. Wenn ich es mit einem Haupt wie folgt ausführen:

public static void main(String[] args) 
{ 
    for (int i = 0; i < 10; i++) { 
     System.out.println(getVersion()); 
    } 
} 

Es funktioniert das erste Mal. Es gibt mir die Ausgabe, die ich will, das sind die Daten aus der http-Anfrage, die in meiner Versions.py Datei geschrieben ist, die der obige Java-Code aufruft. Nach dem zweiten Mal wirft es diesen massiven Fehler (der 950 Zeilen lang ist, aber natürlich werde ich euch nicht foltern). Hier ist der Kern von ihm:

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 

Mein Python Zurückverfolgungs, die am Ende des 950 Zeile Java-Stack-Trace geliefert wird, ist vor allem dieser:

File "<string>", line 18, in get_latest_version 
urllib2.URLError: <urlopen error [Errno -1] Unmapped exception: java.util.concurrent.RejectedExecutionException: event executor terminated> 

Wenn jemand neugierig, die scheinbar störende Zeile in mein get_latest_version ist nur:

handler = urllib2.urlopen(request) 

Seit dem Server, wobei der Code laufen ruft (von cherrypy) ist auf dem lokalen Host im Netzwerk, kann ich sehen, wie es ist, die Interaktion mit mein Server. Es sendet tatsächlich zwei Anfragen (und wirft die Ausnahme gleich nach der zweiten).

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" 

Während ich wahrscheinlich nie diesen Code in einer Schleife laufen gehen, ich bin sehr neugierig, wie zwei Dinge:

  • Sind der betreffende Code meines Python oder Java-Code? Oder könnte es überhaupt ein Problem mit Jython sein?
  • Was bedeutet die Ausnahme (es sieht wie eine Java-Ausnahme aus)? Warum wird es geworfen, wenn es ist? Gibt es eine Möglichkeit, eine solche Schleife funktionieren zu lassen? Könnte das besser geschrieben werden?
+0

Es ist möglich, dass Sie die Ressource zu schnell zuzugreifst, dass in dem ersten Aufruf von 'getVersion()' Du bekommst eine Sperre für die Datei, die noch nicht freigegeben wurde. Können Sie versuchen, [Thread.sleep] (https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep%28long%29) oder [Thread.yield] (https : //docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield%28%29) nach 'getVersion()' in der Schleife? – DaedalusUsedPerl

+0

@DaedalusUsedPerl Ich werde versuchen, den Thread zu schlafen, wie lange denkst du, dass ich das tun sollte? 2-3 Sekunden vielleicht? – Zizouz212

+0

Selbst eine Sekunde ist vielleicht zu viel, aber ich bin mir nicht sicher. Probieren Sie 2 aus und passen Sie sie an, um sie anzupassen. – DaedalusUsedPerl

Antwort

7

Die Python-Bibliothek urllib2, die Sie verwenden, verwendet Netty.

Netty ein Problem hat, die weithin bekannt ist:

Nach all diese Links NettyHttpClient nicht fr von Zeit zu Zeit nach dem Schließen. Es sieht aus wie Netty erholt sich nach einiger Zeit und einige Anwendungen funktionieren nur normal mit diesem Problem. Jedenfalls sieht es instabil aus.


F: Ist der fehlerhafte Code mein Python- oder Java-Code? Oder könnte es überhaupt ein Problem mit Jython sein?

A: Das Problem wird von der Jython-Bibliothek urllib2 verursacht, die Netty verwendet.


F: Was bedeutet die Ausnahme (es sieht wie eine Java-Ausnahme aus)? Warum wird es geworfen, wenn es ist?

A: urllib2 verwendet intern Netty. Netty wird in Java geschrieben und löst diese Java-Ausnahme aus. Netty verwendet einen eigenen Thread-Executor, der nach dem Schließen einer Anfrage für einige Zeit heruntergefahren und unbrauchbar ist. Du hast genau diese Zeit getroffen.


F: Gibt es eine Möglichkeit, eine Schleife wie diese arbeiten zu lassen? Könnte das besser geschrieben werden?

A: Ich würde versuchen, Requests Bibliothek zu verwenden.

+0

Das beantwortet meine Frage * nicht * alle. Ich suche nach einer Erklärung für die Ausnahme und warum es nicht funktioniert. Das hilft mir nicht weiter. Was löst die Ausnahme aus? Warum? Ist es ein Fehler bei der Implementierung? Interessanterweise scheint es, als hätten Sie sich nicht die Mühe gemacht, die Frage zu lesen: Ich habe jeweils eine einzige Jython-Umgebung, nicht mehrere gleichzeitig. – Zizouz212

+0

@ Zizouz212 Es war nicht einfach, das Problem ohne Ihren Python-Code vollständig zu analysieren. Trotzdem sieht es so aus, als hätte ich die Ursache gefunden. * Ich habe die Antwort komplett umgeschrieben. * Hoffe, es wird jetzt helfen. –

+0

Danke @OlegRudenko. Interessant, das Problem zu lesen und nett zu Netty zu verfolgen. Ich würde es mir als nächstes ansehen, aber die Zeit war knapp. –

0

Versuchen der Dolmetscher frisch initialisiert Systemzustand jedes Mal, so dass Sie es schaffen:

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