2014-11-04 24 views
5

Se provo a valutare il seguente codice nel mio emacs cider-repl, nil viene restituito, come previsto, ma nessuna stampa avviene nel repl buffer o nella console. Come posso rendere questa stampa come previsto?Perché non riesco a stampare da thread in background in Clojure Cider REPL in emacs?

(dotimes [i 5]                                   
    (.start                                    
    (Thread.                                   
    (fn []                                    
     (Thread/sleep (rand 500))                              
     (println (format "Finished %d on %s" i (Thread/currentThread))))))) 
;=> nil 

Questo funziona bene, tuttavia:

(println (format "Finished 1 on %s" (Thread/currentThread))) 
;=> Finished 1 on Thread[nREPL-worker-18,5,main] 
----------- mini-buffer ----------------- 
nil 

risposta

10

Il comportamento di println è quello di utilizzare una var vincolato dinamicamente chiamato *out* come flusso di uscita. emacs lega dinamicamente *out* per andare al buffer di repl per il codice valutato nel buffer repl, ma se si crea un thread, il thread *out* ottiene il binding root di *out*, che nel caso del sidro non sarà il buffer di repl.

Se hai iniziato la repl utilizzando cider-jack-in, quando si guarda a voi tampone lista ci dovrebbe essere un buffer con un nome come *nrepl-server* che contiene l'uscita della radice *out* vincolante. Ecco il contenuto della miniera dopo l'esecuzione il codice:

nREPL server started on port 52034 on host 127.0.0.1 - nrepl://127.0.0.1:52034 
Finished 1 on Thread[Thread-9,5,main] 
Finished 0 on Thread[Thread-8,5,main] 
Finished 2 on Thread[Thread-10,5,main] 
Finished 3 on Thread[Thread-11,5,main] 
Finished 4 on Thread[Thread-12,5,main] 

Se non è stato utilizzato cider-jack-in, l'uscita stampare al terminale in cui è stato avviato il processo di nrepl.

+0

Grazie mille! Questo risolve il mistero e tu mi hai appena insegnato qualcosa sia su Clojure che su Emacs.C'è un modo per riassociare la variabile * out * per i thread in background da stampare anche sul repl repl buffer? – kurofune

+0

'* out *' può essere impostato con 'binding', come qualsiasi altra var dinamica. La risposta di @ amalloy fa un buon lavoro nel mostrare quella parte che penso. – noisesmith

+0

proprio sopra. Entrambi avete chiaramente risolto questo per me. Grazie. – kurofune

9

*out* è la variabile dinamica che determina dove viene eseguita l'uscita da println e funzioni simili. È legato al filo in un punto che causa la restituzione di materiale in emacs per la visualizzazione da parte del sidro; se si avvia un nuovo thread, quell'associazione non è presente e l'output va altrove (probabilmente allo stdout del server nrepl emacs/leiningen avviato in background).

È possibile risolvere questo in alcuni modi. Si potrebbe cogliere il valore della *out* dal thread padre e quindi passarlo insieme al thread bambino in una chiusura, e ricollegare *out* ad esso:

(let [out *out*] 
    (.start (Thread. (fn [] 
        (binding [*out* out] 
         (println "test")))))) 

Oppure si può utilizzare un future invece di iniziare il filo da soli : Clojure trasmette automaticamente collegamenti locali thread-thread a nuovi thread avviati per un futuro.

+0

Ehi amico, potresti mostrarmi un esempio di codice usando il futuro? Ho giocato con esso al repl, ma non riuscivo a capirlo. – kurofune

0

Se si utilizza Figwheel, poi facendo prn/println in ring handlers (che sono in realtà simili all'esempio di Thread mostrato sopra) può anche essere inghiottito da Fighweel stesso. Controlla project.clj del tuo progetto (cerca la chiave: server-logfile all'interno della mappa: figwheel), dove puoi controllare se out dovrebbe andare al repl o in un file di log. Si prega di notare che questo si applica solo se si utilizza figwheel, altrimenti la stampa sul REPL funziona ovviamente.

Vedere la mia risposta su questa domanda per maggiori dettagli: Output compojure server print statements into figwheel terminal?