zsh lento facendo eval con path

Aug 25 2020

Ho riscontrato un problema di prestazioni per un po 'di tempo durante l'esecuzione del completamento automatico in una cartella utilizzando zsh. Infine, ho dedicato del tempo, per cercare di capire COSA ha causato il problema, e COME risolverlo. Purtroppo devo fermarmi al COSA, il COME risolvere rimane un punto interrogativo.

Quando eseguo zsh in debug con la traccia abilitata (e disabilito my .zshrc.local), riesco a vederlo chiaramente:

Quando premo il doppio TAB, facendo $ cd ~/Documents/<TAB>, ottengo:

....
+_cd:88> eval 'dir=( ~Documents/ )'
+(eval):1> dir=( '~Documents/' )
....

L'ultimo impiega circa 3 secondi per rispondere.

Ciò accade a tutti i livelli di completamento automatico della cartella ( cd a/<TAB>, cd a/b/<TAB>,... ), non con cd <TAB>.

Ho provato a impostare il set -o magicequalsubst.

Risposte

1 StéphaneChazelas Aug 26 2020 at 14:36

La riga 88 della _cdfunzione di completamento nelle versioni correnti dizsh si trova in una sezione che viene raggiunta solo quando l' cdablevarsopzione è abilitata.

Con quell'opzione attiva, cd usernameo cd varverrebbe cdnella home directory usernamedell'utente o nel percorso memorizzato $varse esistessero quegli user/var e non ci fossero username/ vardirectory nella directory corrente o $cdpath. In altre parole, cd foosi comporta come cd ~foose foonon esistesse come directory (in .o $cdpath).

Ora, è solo qualcosa che viene fatto per cd/ pushd. Quando _cdcostruisce l'elenco dei possibili completamenti e sei entrato Documents/fin qui, deve proporti l'elenco delle sottodirectory della Documentscartella, ma anche, visto che hai abilitato cdablevars, l'elenco delle sottodirectory della home directory Documentsdell'utente o del directory memorizzata nella $Documentsvariabile, se presente.

Ecco perché lo sta facendo eval 'dirs=( ~Documents )'.

Ora, immagino che l'espansione potrebbe essere lenta se ti trovi su un sistema che dispone di un ampio database di utenti in rete senza memorizzazione nella cache, ad esempio (LDAP, NIS + ...). zshcercherà Documentsnel suo elenco di variabili che dovrebbero essere veloci anche se hai milioni di variabili poiché zsh usa una tabella hash e chiamerà getpwnam("Documents")per recuperare la home directory Documentsdell'utente, che è la parte che è probabilmente lenta nel tuo caso. Puoi confermare provando id Documentsquale dovrebbe effettuare la stessa getpwnam()chiamata.

Personalmente starei alla larga da questa cdablevarsopzione in quanto è destinata a darti brutte sorprese un giorno o l'altro. Senza di esso, puoi sempre fare cd ~usero cd ~var, e trovo molto meglio richiederlo esplicitamente quando vuoi cdentrare in qualcosa di diverso dalla directory data come argomento.

Questo cdablevarsera già nella primissima versione del zsh1990, ispirata a tcshquello che fa per impostazione predefinita. Precede l'espansione di ~var. cdablevarsdovrebbe essere considerato come un manufatto storico IMO.

Per quanto riguarda come correggere la lentezza di getpwnam(), potresti esaminare la messa a punto del database del servizio dei nomi. Ad esempio, se si utilizza sssd, è possibile aumentare l' entry_negative_timeoutimpostazione che determina per quanto tempo memorizzare nella cache le informazioni che l' Documentsutente non esiste prima di interrogare nuovamente il back-end. 3 secondi sembrano comunque eccessivi per una query del database utente, suggerendo che potresti avere un problema di configurazione o che il server del provider non è disponibile e l'eventuale meccanismo di fallback non è configurato in modo ottimale.