___ qstnhdr ___ Richiede multithreading / concorrenza per l'implementazione del linguaggio di scripting ______ qstntxt ___
Ecco l'accordo: sto progettando il mio linguaggio di scripting / interpretato per divertimento. Sono solo in fase di pianificazione in questo momento; Voglio essere sicuro di avere una strong presa su esattamente come implementerò tutto prima di iniziare la programmazione.
Ciò a cui sono attualmente alle prese è la concorrenza. Mi sembra un modo semplice per evitare che le prestazioni imprevedibili offerte dalla garbage collection siano quelle di mettere il garbage collector nel proprio thread e farlo funzionare contemporaneamente all'interprete stesso. (Per essere chiari, non ho intenzione di consentire agli script di essere multithreading stessi, vorrei semplicemente mettere un garbage collector per lavorare in un thread diverso rispetto all'interprete.) Questa non sembra essere una strategia comune per molti linguaggi di scripting, probabilmente per ragioni di portabilità; Probabilmente scriverei inizialmente l'interprete nel framework di threading UNIX / POSIX e poi lo porterei su altre piattaforme (Windows, ecc.) Se necessario.
Qualcuno ha qualche idea in questo numero? I guadagni che otterrò sfruttando la concorrenza potrebbero essere vanificati dai problemi di portabilità che inevitabilmente si presenteranno? (Su quella nota, ho davvero ragione nel ritenere che avrei sperimentato grandi guadagni in termini di prestazioni con un garbage collector concorrente?) Devo andare avanti con questa strategia o allontanarmi da essa?
scrivere tutto ciò che è multithread è difficile
Riesco a pensare ad almeno una condizione di gara in cima alla mia testa di cui devi essere a conoscenza:
- c'è un oggetto
CAS
con campo %code%
- il GC ha appena iniziato la fase contrassegnata e ha esaminato il campo %code% e sta attualmente esaminando qualche altra parte dell'albero degli oggetti
- nel frattempo l'interprete ha assegnato un nuovo oggetto %code% e lo script lo assegna a %code% e la variabile locale in cui si trova va fuori ambito (eliminando qualsiasi altro riferimento a %code% )
- il GC termina e non noterà la modifica a %code% così %code% non verrà contrassegnato come vivo
- B viene ripulito e hai un puntatore pendente in %code%
questo non ha bisogno di essere allocazione (qualsiasi metodo per diventare l'unico proprietario di un %code% non marcato e quindi l'assegnazione a un campo già esaminato causerà problemi)
questo può essere risolto mettendo un qualsiasi oggetto gestito dall'interprete (non ancora segnato vivo nello sweep) in un elenco da esaminare in modo che venga segnato vivo durante lo sweep
quindi in sostanza in ogni oggetto hai un campo bit con un flag "vivo" e un flag "gestito da interprete"
e su ogni oggetto che lo script utilizza l'interprete dovrà fare
%pre%
questo ritarderà la pulizia di alcuni oggetti ma è accettabile
Sono sicuro che ci sono molte altre cose di cui essere a conoscenza (come i normali effetti di visibilità della memoria) che renderanno le cose più difficili e questo è probabilmente un grande motivo per cui i GC concorrenti sono rari
am I really correct in my assumption that I would experience great
performance gains with a concurrent garbage collector?
Io non la penso così
Innanzitutto, anche se riesci a creare un GC totalmente gratuito, otterrai solo "grandi guadagni in termini di prestazioni" se gli attuali GC in-thread fossero ottimi sink di prestazioni. L'esperienza nelle moderne implementazioni di GC indica diversamente. Alcuni di questi sono abbastanza leggeri.
In secondo luogo, per natura, un GC tocca molta memoria mentre gli altri thread stanno lavorando su di esso, quindi devi stare molto attento a evitare condizioni di gara abbastanza brutte. Qualsiasi blocco che hai messo lì sarà notevolmente contento, rendendoli operazioni costose. Anche se riesci a utilizzare strutture senza blocco (non per i deboli di cuore!), L'accoppiamento stretto tra il thread GC e l'interprete renderebbe ogni %code% un'operazione un punto di caching della cache.
A mio parere, la complessità aggiuntiva necessaria per un GC out-of-thread li rende poco pratici a meno che non si desideri utilizzare il multi-threading completo. In questo caso, hai già pagato la maggior parte dei costi di contesa, in modo da dedicare un thread per GC ha un senso.
Si noti che le implementazioni di JVM con molto multithreading (come quella di Azul ) hanno un GC out-of-thread, ma comunque prova a fare la maggior parte degli in-thread di gestione per evitare il modello fail-and-retry che le strutture prive di lock sono soggette a carichi pesanti.
Questa è una vecchia domanda, ma se sei ancora interessato, potresti consultare Qore , che è una lingua interpretata con supporto fondamentale per multithreading e ha anche un approccio unico alla raccolta dei rifiuti ( Raccolta prompt ) che consente alla lingua di supportare RAII idioma (distruttori di tipo c ++ per la gestione delle risorse e programmazione eccezionalmente sicura) anche nel caso di grafici di oggetti diretti ciclici.
Dal momento che non hai (o non è più tardi da quando la domanda è vecchia!) pianifichi di rendere la tua lingua multi-threaded, l'analisi del grafico deterministico sarebbe molto più semplice, perché a causa della sua natura multithread, il deadlock avoidance and notification gli aspetti dell'algoritmo di raccolta rapida di Qore aggiungono una notevole complessità a una sfida già complessa.
Quindi non avresti bisogno di un thread di garbage collection separato e potresti ancora implementare il supporto per i distruttori simili a C ++ nella tua lingua per supportare l'idioma RAII (se applicabile).