Domanda

Soggetto:

Sto cercando di implementare una pianificazione del lavoro di base in Java per gestire attività pianificate persistenti ricorrenti (per un progetto di apprendimento personale).Non voglio utilizzare librerie (pronte all'uso) come Quartz/Obsidian/Cron4J/etc.

Obbiettivo:

  • Il lavoro deve essere persistente (per gestire l'arresto del server)
  • Il tempo di esecuzione del lavoro può richiedere fino a ~2-5 minuti.
  • Gestire una grande quantità di lavoro
  • Multi thread
  • Leggero e veloce ;)

Tutto il mio lavoro è in un database MySQL.

JOB_TABLE (id, name, nextExecution,lastExecution, status(IDLE,PENDING,RUNNING))

Passo dopo passo:

  1. Recupera ogni lavoro da “JOB_TABLE" Dove “nextExecution > now” AND “status = IDLE“.Questo passaggio viene eseguito ogni 10 minuti da un singolo thread.

  2. Per ogni lavoro recuperato, inserisco un nuovo thread in a ThreadPoolExecutor quindi aggiorno lo stato del lavoro su "PENDING" nel mio "JOB_TABLE”.

  3. Quando il thread del lavoro è in esecuzione, aggiorno lo stato del lavoro su "RUNNING”.

  4. Una volta terminato il lavoro, aggiorno il file lastExecution con l'ora corrente, ne ho impostato uno nuovo nextExecution tempo e cambio lo stato del lavoro in "IDLE”.

All'avvio del server, inserisco ciascun lavoro IN ATTESA/IN ESECUZIONE nel file ThreadPoolExecutor.

Domanda/Osservazione:

  • Passo 2 :ThreadPoolExecutor gestirà una grande quantità di thread (~ 20000)?
  • Dovrei usare una soluzione NoSQL invece di MySQL?
  • È la soluzione migliore per affrontare questo caso d'uso?

Questa è una bozza, non c'è alcun codice dietro.Sono aperto a suggerimenti, commenti e critiche!

È stato utile?

Soluzione

Ho fatto un compito simile al tuo su un progetto reale, ma in .NET.Ecco cosa ricordo riguardo alle tue domande:

Passo 2 :ThreadPoolExecutor gestirà una grande quantità di thread (~ 20000)?

Abbiamo scoperto che il pool di thread integrato di .NET era l'approccio peggiore, poiché il progetto era un'applicazione web.Motivo:l'applicazione Web si basa sul pool di thread integrato (che è statico e quindi condiviso per tutti gli usi all'interno del processo in esecuzione) per eseguire ciascuna richiesta in thread separati, mantenendo al tempo stesso un riciclo efficace dei thread.L'utilizzo dello stesso pool di thread per la nostra elaborazione interna lo avrebbe esaurito e non avrebbe lasciato thread liberi per le richieste degli utenti o ne avrebbe rovinato le prestazioni, il che era inaccettabile.

Dato che sembra che tu stia eseguendo molti lavori (20k sono tanti per una singola macchina), dovresti assolutamente cercare un pool di thread personalizzato.Non c'è bisogno di scriverne una tu, scommetto che ci sono soluzioni già pronte e scriverne una va ben oltre ciò che il tuo progetto di studio richiederebbe* vedere i commenti (se ho capito bene stai portando avanti un progetto scolastico o universitario).

Dovrei usare una soluzione NoSQL invece di MySQL?

Dipende.Ovviamente devi aggiornare lo stato del lavoro contemporaneamente, quindi avrai accesso simultaneo a una singola tabella da più thread.I database possono adattarsi abbastanza bene a questo, supponendo che tu abbia fatto bene le tue cose.Ecco cosa mi riferisco a farlo nel modo giusto:

  • Progetta il tuo codice in modo che ogni lavoro influisca solo sul proprio sottoinsieme di righe nel database (questo include altre tabelle).Se sei in grado di farlo, non avrai bisogno di alcun blocco esplicito a livello di database (sotto forma di livelli di serializzazione delle transazioni).Puoi anche applicare un livello di serializzazione liberale che potrebbe consentire letture sporche o fantasma, che verranno eseguite più velocemente.Ma attenzione, è necessario assicurarsi attentamente che nessun lavoro concorra sulle stesse righe.Questo è difficile da ottenere nei progetti della vita reale, quindi probabilmente dovresti cercare approcci alternativi al blocco del database.

  • Utilizzare la modalità di serializzazione delle transazioni appropriata. La modalità di serializzazione delle transazioni definisce il comportamento di blocco a livello di database.Puoi impostarlo per bloccare l'intera tabella, solo le righe interessate o niente del tutto.Usalo con saggezza, poiché qualsiasi uso improprio potrebbe compromettere la coerenza, l'integrità e la stabilità dei dati dell'intera applicazione o del server db.

  • Non ho familiarità con il database NoSQL, quindi posso solo consigliarti di ricercare le capacità di concorrenza e mapparle al tuo scenario.Potresti ritrovarti con una soluzione davvero adatta, ma devi verificare in base alle tue esigenze.Dalla tua descrizione, dovrai supportare operazioni simultanee sui dati sullo stesso tipo di oggetti (qual è l'analogo per una tabella).

È la soluzione migliore per affrontare questo caso d'uso?

Sì e no.

  • , poiché incontrerai uno dei compiti difficili che gli sviluppatori devono affrontare nel mondo reale.Ho lavorato con colleghi con più di 3 volte la mia esperienza ed erano più riluttanti di me a svolgere attività multi-threading, lo odiavano davvero.Se ritieni che quest'area sia interessante per te, giocaci, impara e migliora quanto devi.

  • NO, perché se stai lavorando a un progetto di vita reale, hai bisogno di qualcosa di affidabile.Se hai così tante domande, ovviamente avrai bisogno di tempo per maturare ed essere in grado di produrre una soluzione stabile per un compito del genere.Il multi-threading è un argomento difficile per molte ragioni:

    • È difficile eseguire il debug
    • Presenta molti punti deboli, è necessario esserne consapevoli
    • Potrebbe essere una seccatura per altri sviluppatori assistere o lavorare con il tuo codice, a meno che tu non rispetti le regole comunemente accettate.
    • La gestione degli errori può essere complicata
    • Il comportamento è imprevedibile/indeterministico.

    Esistono soluzioni esistenti con un elevato livello di maturità e affidabilità che rappresentano l'approccio preferito per progetti reali.Lo svantaggio è che dovrai impararli ed esaminare quanto sono personalizzabili per le tue esigenze.

Ad ogni modo, se hai bisogno di farlo a modo tuo, e poi trasferire i tuoi risultati in un progetto reale, o in un tuo progetto, posso consigliarti di farlo in modo collegabile.Usa l'astrazione, programmazione alle interfacce e altre pratiche per disaccoppiare la propria implementazione specifica dalla logica che imposterà i lavori pianificati.In questo modo, puoi adattare la tua API a una soluzione esistente se questo diventa un problema.


E ultimo, ma non meno importante, non ho visto alcuna previsione sulla gestione degli errori da parte tua.Pensa e ricerca cosa fare se un lavoro fallisce.Almeno aggiungi uno stato "FAILED" o qualcosa che persista in questo caso.La gestione degli errori è complicata quando si tratta di thread, quindi sii approfondito nella ricerca e nelle pratiche.

Buona fortuna

Altri suggerimenti

È possibile dichiarare la dimensione massima del pool con ThreadPoolExecutor # setmaximumPoolsize (INT). Come Integer.MAX è più grande del 20000, quindi tecnicamente sì, può.

L'altra domanda è che la tua macchina appare tante thread da eseguire. Avrai fornito abbastanza RAM in modo che ogni battistrada si assegnerà sullo stack.

te non dovrebbe essere problema per indirizzo ~ 20.000 fili sul desktop o sul computer portatile moderno ma sul dispositivo mobile potrebbe essere un dispositivo mobile problema.

DOC:

nucleo e massimi dimensioni del pool

.

Un threadpoolexecutor verrà automaticamente Regolare la dimensione della piscina (vedere GetPoolsize ()) Secondo il set dei limiti da CorePoolsize (vedi getcorepoolsize ()) e MaximumPoolsize (vedi getmaximumPoolsize ()). Quando è presentato un nuovo compito in metodo ESEGUIRE (JAVA.LANG.Runnable) e meno dei fili di CorePoolsize Esecuzione, viene creato un nuovo thread per gestire la richiesta, anche se altro I fili del lavoratore sono inattivi. Se ci sono più di corepoolsize ma meno di MaximumPoolsize Threads in esecuzione, verrà creata una nuova filettatura Solo se la coda è piena. Impostando CorePoolsize e MaximumPoolsize Lo stesso, si crea un pool di fili a formato fisso. IMPOSTANDO MaximumPoolsize a un valore essenzialmente illimitato come Integer.max_value, si consente al pool di accogliere un arbitrario numero di compiti simultanei. Più tipicamente, nucleo e pool massimo Le dimensioni sono impostate solo dopo la costruzione, ma possono anche essere cambiate Usando dinamicamente SetCoRepoolSize (INT) e SetMaximumPoolsize (INT).

Altro < / a>

Informazioni sul DB. Creare una soluzione che non dipende dalla struttura DB. Quindi puoi creare due ambienti e misurarlo. Inizia con la tecnologia che conosci. Ma continua a aprire ad altre soluzioni. All'inizio le relazioni DB dovrebbero tenere il passo con le prestazioni. E se lo mangi correttamente, non dovrebbe essere un problema in seguito. Il NOSQL è usato per funzionare con dati davvero grandi. Ma il meglio per te è quello di creare entrambi ed eseguire alcuni test di performing.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top