2015-08-27 17 views
15

Ho il seguente codice:Perché questo ciclo Jython ha esito negativo dopo una singola esecuzione?

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

Per ragioni di completezza, sto aggiungendo il codice 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() 

Esso funziona perfettamente, ma solo il 10% del tempo. Se lo eseguo con un main come segue:

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

Funziona la prima volta. Mi dà l'output che desidero, ovvero i dati della richiesta http scritta nel mio file Versions.py, che il codice java sopra chiama. Dopo la seconda volta, questo errore enorme (che è lungo 950 linee, ma ovviamente non ti torturerò). Ecco l'essenza di esso:

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 

mio Python traceback che viene fornita alla fine del 950 linea di Java stack trace è principalmente questo:

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

Se qualcuno è curioso, la linea apparentemente incriminata in la mia è solo get_latest_version:

handler = urllib2.urlopen(request) 

Poiché il server che il codice sta chiamando è gestito (da CherryPy) sul localhost sulla mia rete, posso vedere come si sta interagendo con il mio server In realtà invia due richieste (e lancia l'eccezione subito dopo il secondo).

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" 

Mentre sto mai andare a eseguire questo codice in un ciclo probabilmente, sono abbastanza curioso di sapere due cose:

  • è il codice incriminato il mio codice Python o Java? O potrebbe essere solo un problema con Jython del tutto?
  • Che cosa significa l'eccezione (sembra un'eccezione java)? Perché viene lanciato quando è? C'è un modo per fare un ciclo come questo? Potrebbe essere scritto meglio?
+0

E 'possibile che si sta accedendo alla risorsa troppo in fretta, che nella prima chiamata a 'getVersion()' hai un blocco sul file che non è stato ancora rilasciato. Puoi provare a chiamare [Thread.sleep] (https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep%28long%29) o [Thread.yield] (https : //docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield%28%29) dopo 'getVersion()' nel ciclo? – DaedalusUsedPerl

+0

@DaedalusUsedPerl Proverò a dormire il thread, per quanto pensi che dovrei farlo? Forse 2-3 secondi? – Zizouz212

+0

Anche un secondo potrebbe essere eccessivo, ma non ne sono sicuro. Prova 2 e regola su/giù per adattarsi. – DaedalusUsedPerl

risposta

7

La libreria python urllib2, che viene utilizzata, utilizza Netty.

Netty ha un problema, che è ampiamente conosciuto:

Secondo tutti questi collegamenti NettyHttpClient fallisce fr om una volta dopo la chiusura. Sembra che Netty si riprenda dopo un po 'di tempo e alcune applicazioni funzionano normalmente con questo problema. Ad ogni modo sembra instabile.


D: Il codice incriminato è il mio codice Python o Java? O potrebbe essere solo un problema con Jython del tutto?

A: Il problema è causato dalla libreria Jython urllib2, che utilizza Netty.


D: Che cosa significa l'eccezione (sembra un'eccezione java)? Perché viene lanciato quando è?

A: urllib2 utilizza internamente Netty. Netty è scritto in Java e genera questa eccezione Java. Netty utilizza il proprio Thread Executor, che viene spento e inutilizzabile per un certo periodo di tempo dopo la chiusura di una richiesta. Colpisci esattamente questa volta.


D: C'è un modo per rendere un ciclo simile a questo? Potrebbe essere scritto meglio?

A: Vorrei provare a utilizzare la libreria Requests.

+0

Questo non risponde alla mia domanda * a * tutti. Sto cercando una spiegazione per l'eccezione e perché non funziona. Questo non fa nulla per aiutarmi. Cosa lancia l'eccezione? Perché? È un bug con l'implementazione? È interessante notare che sembra che non ti sei preso la briga di leggere la domanda: ho un singolo ambiente Jython alla volta, non più allo stesso tempo. – Zizouz212

+0

@ Zizouz212 Non è stato facile analizzare il problema completamente senza il tuo codice Python. Comunque sembra che ho trovato la causa. * Ho completamente riscritto la risposta. * Spero, sarà d'aiuto ora. –

+0

Grazie a @OlegRudenko. Interessante leggere la causa del problema e tracciarlo su Netty. Avrei intenzione di guardarlo dopo, ma è finito il tempo. –

0

Provare a dare l'interprete uno stato sistema appena inizializzato ogni volta che si crea:

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