25

Penso che Haskell sia un linguaggio bellissimo e, a giudicare dai benchmark, le sue implementazioni possono generare codice veloce.Haskell è appropriato per le applicazioni di lunga durata?

Tuttavia, mi chiedo se sia appropriato per le applicazioni di lunga durata o se inseguiremo tutte le potenziali perdite indotte dalla pigrizia, che uno potrebbe ignorare in un'applicazione di breve durata, dimostrarsi frustrante?

This Reddit comment Echos le mie preoccupazioni:

Non appena si dispone di più di una funzione che si fa chiamare ricorsivamente, il profilo mucchio cessa di dare alcun aiuto individuare dove la perdita si sta verificando.

(che tutta la discussione sembra penetranti e franca)

Sono personalmente interessato a calcolo ad alte prestazioni, ma credo che i server e HPC avere questo requisito in comune.

Se Haskell è appropriato per tali applicazioni, vi sono esempi che dimostrano questo punto, cioè applicazioni che

  1. necessario eseguire per giorni o settimane, richiedendo quindi l'eliminazione di tutte le perdite rilevanti (il momento in cui il il programma trascorre dormendo o in attesa di qualche libreria C sottostante per tornare ovviamente non conta)
  2. non banali (se l'applicazione è semplice, lo sviluppatore potrebbe solo indovinare l'origine della perdita e tentare varie correzioni. Non credo che questo approccio si adatti bene e la disponibilità del profilo dell'heap nell'individuare l'origine della/e perdita/e con più [reciprocamente] ricorre Le funzioni ive sembrano essere di particolare interesse, come da discussione Reddit sopra)

Se Haskell non è appropriato per tali applicazioni, allora perché?

Update: Il framework web server Yesod per Haskell, che è stato messo davanti come esempio, may have issues with memory. Mi chiedo se qualcuno ha testato l'utilizzo della memoria dopo aver servito le richieste continuamente per giorni.

+2

Sembra un po 'come se un sistema con un garbage collector sia appropriato: a causa della gente 'gc' normalmente non si distruggono oggetti che non sono più necessari: contano che alla fine il gc li troverà. Ma questo può comportare un gran numero di oggetti heap che sono attivi solo perché un riferimento non è impostato su 'null' rendendo tutti questi oggetti inutili. –

+6

La pigrizia non significa perdite di spazio, proprio come la severità no. Esistono diverse tecniche per gestire entrambi i tipi di modelli di memoria. Il modo in cui scrivi la tua domanda determina se la tua applicazione sarà in grado di funzionare per lunghi periodi di tempo. So che [Facebook utilizza Haskell] (https://github.com/facebook/Haxl) come uno strato intermedio tra più archivi di dati e alcuni dei loro servizi di frontend, ma non so se si tratta di processi di breve durata. La mia ipotesi è che avrebbero bisogno di essere a lungo in esecuzione, quindi se questo è il caso avresti un esempio abbastanza solido proprio lì. – bheklilr

+0

@bheklilr: Non penso che MaxB si riferisca a perdite di spazio: Haskell gestisce correttamente la memoria (o dovrebbe provenire da un pov teorico), ma può richiedere anni prima che gli oggetti morti vengano riciclati. –

risposta

8

Il server Web Warp dimostra che Haskell è appropriato per le applicazioni di lunga durata.

Quando le applicazioni Haskell hanno perdite di spazio, può essere difficile da rintracciare la causa, ma una volta che la causa è nota di solito è banale per risolvere (la correzione più difficile che abbia mai dovuto usare era di applicare zip [1..] a un elenco e ottenere la lunghezza dall'ultimo elemento invece di utilizzare la funzione length). Ma le perdite di spazio sono in realtà molto rare nei programmi Haskell. Generalmente è più difficile creare deliberatamente una perdita di spazio piuttosto che fissarne uno accidentale.

+0

'Il server Web Warp dimostra ...' Ci sono siti Web occupati che lo usano? – MaxB

+2

https://github.com/yesodweb/yesod/wiki/Powered-by-Yesod ha un elenco incompleto di siti Web che utilizzano il framework Yesod (che sarebbe difficile da utilizzare con un altro server web). Nessuno sembra essere così impegnato, ma a volte è difficile da dire. D'altra parte: in parametri di warp si gestiscono più richieste al secondo di nginx, tranne che su server single core. Su 10 server core: warp è 5 volte più veloce di nginx. –

5

La maggior parte delle app di lunga durata sono richieste. Ad esempio, i server HTTP associano tutti i dati transitori a una richiesta HTTP. Una volta terminata la richiesta, i dati vengono gettati via. Quindi, almeno per quel tipo di app di lunga durata, qualsiasi lingua non avrà perdite di spazio. Perdere tutto ciò che si desidera nel contesto di una singola richiesta. Finché non si creano riferimenti globali a dati per richiesta, non si verificheranno perdite.

Tutte le scommesse sono disattivate se si modifica lo stato globale. Questo deve essere evitato per molte ragioni, ed è raro in tali app.

+0

Non è un programmatore web, ma penso che molti server HTTP debbano conservare alcune informazioni dopo aver fornito una richiesta: registrazione, nuovo contenuto (come in questo sito), articoli lasciati in magazzino, ecc. – MaxB

+0

@Carsten, quindi forse stiamo implementando un database o qualcosa del genere. – luqui

+0

@luqui ???beh, sembra che io sia lo strano tipo di ragazzino con cui non vuoi giocare qui - quindi ok sto già zitto – Carsten

2

Ho un servizio scritto in haskell che funziona per mesi senza alcun problema specifico di haskell. C'è stato un periodo in cui ha funzionato per 6 mesi senza alcuna attenzione, ma poi l'ho riavviato per applicare l'aggiornamento. Contiene un'API HTTP stateless, ma ha anche un'interfaccia websocket statefull, quindi mantiene uno stato di vita lungo. Le sue fonti sono chiuse, quindi non posso fornire un collegamento, ma la mia esperienza haskell funziona bene per le applicazioni di lunga durata.

La pigrizia non è un problema per me, ma è perché so come gestirlo. Non è difficile, ma richiede una certa esperienza.

Anche le librerie su hackage hanno qualità diverse e tenere sotto controllo le dipendenze è una cosa importante. Cerco di evitare le dipendenze a meno che non siano realmente necessarie, e ispeziono la maggior parte del loro codice (tranne un numero di pacchetti ampiamente usati, la maggior parte di essi sono o librerie di base o parte di Haskell Platform, sebbene controlli anche il loro codice - solo per imparare nuove cose.)

Anche se ci sono casi in cui GHC (l'implementazione più utilizzata) non funziona abbastanza bene. Ho avuto problemi con il tempo di GC quando un'applicazione mantiene uno stato enorme (per lo più in sola lettura) in memoria (c'è un ticket.) Anche molti indicatori stabili possono essere problematici (lo ticket, anche se non l'ho mai sperimentato personalmente.) La maggior parte tempo in cui i casi angolari sono facili da evitare con un design accurato.

In realtà il design dell'applicazione è la cosa più importante per le applicazioni di lunga durata. Il linguaggio di implementazione gioca un ruolo meno importante. Probabilmente è la più grande lezione che ho rivolto negli ultimi anni: la progettazione del software è molto importante e non è molto diversa tra le lingue.

14

"Perdite di spazio" sono semanticamente identiche a qualsiasi altro tipo di problema di utilizzo delle risorse in qualsiasi lingua. Nelle lingue più rigide il GC tende ad allocare e conservare troppi dati (poiché le strutture sono rigide).

Indipendentemente dalla lingua, è necessario eseguire alcuni "burn in" per cercare l'utilizzo delle risorse nel tempo e Haskell non è diverso.

Vedere ad es. xmonad, che viene eseguito per mesi o anni alla volta. È un'app Haskell, ha un piccolo uso di heap e l'ho testata eseguendomi per settimane o mesi con la creazione di profili per analizzare i modelli di heap. Questo mi dà fiducia che l'uso delle risorse è stabile.

In fin dei conti, la pigrizia è un'aringa rossa qui. Utilizza gli strumenti di monitoraggio delle risorse e i test per misurare e convalidare le tue aspettative sulle risorse.

+2

'xmonad' ha una complessità molto bassa (<1KLOC). Non è chiaro come la ricerca di perdite guardando il profiler si riduca, e 'xmonad' non dorma il 99,9% delle volte? (Cosa dice il tuo 'top?)' Xmonad' è davvero il miglior esempio dell'uso di Haskell in questo tipo di applicazione? – MaxB

+0

Il nucleo di xmonad è <1K ed è molto simile al nucleo di un server web. Se hai requisiti diversi per "long run", specifica cosa intendi. –

+1

Ho appena chiarito i requisiti nella domanda. – MaxB

4

Lo è. Esistono 2 tipi di possibili perdite di spazio:

Dati sullo heap. Qui la situazione non è diversa dalle altre lingue che usano GC. (E per quelli che non la situazione è di solito peggiore - se c'è un errore, invece di aumentare l'utilizzo della memoria, il processo potrebbe toccare memoria liberata o viceversa e solo crash gravemente.)

Thunks non valutati. Certo, ci si può sparare al piede, ovviamente si devono evitare situazioni note che producono grandi thunk come foldl (+) 0. Ma non è difficile prevenirlo, e per altre fughe direi che in realtà è più facile che in altre lingue, quando ci si abitua.

O si dispone di un calcolo a lunga esecuzione, pesante o di un servizio che risponde alle richieste.Se hai un calcolo a lunga esecuzione, di solito hai bisogno di risultati immediatamente mentre li calcolhi, il che costringe la loro valutazione.

E se si dispone di un servizio, il suo stato è generalmente ben contenuto, quindi è facile assicurarsi che venga sempre valutato al termine di una richiesta. In effetti, Haskell lo rende più facile rispetto ad altre lingue: in Haskell, non è possibile avere componenti del programma che mantengano il proprio stato interno. Lo stato globale dell'applicazione viene inserito come argomento in una sorta di ciclo principale oppure viene memorizzato utilizzando IO. E poiché una buona progettazione di un'applicazione Haskell limita e localizza il più possibile il IO, rende lo stato facilmente controllabile.


Un altro esempio: il progetto Ganeti (di cui io sono uno sviluppatore) utilizza diversi Haskell demoni a lungo in esecuzione.

Dalla nostra esperienza, le perdite di memoria sono state molto rare, se avessimo avuto problemi, di solito era con altre risorse (come i descrittori di file). L'unico caso un po 'recente che ricordo è stato il demone di monitoraggio che perdeva memoria nel momento in cui raccoglieva dati, ma nessuno li ha guardati (il che avrebbe costretto la loro valutazione). Il fix was rather simple.

Problemi correlati