Rende il programma multithread asincrono

4

Esiste un'applicazione che elabora le richieste TCP / IP in base a qualche logica, e piuttosto sempre si collega a DB.

L'architettura è molto comune: un client - > un thread di elaborazione - > una connessione DB - > un thread DB per elaborare una query (il thread DB esiste all'interno dell'applicazione DBMS e menzionato qui per mostrare l'insufficienza delle prestazioni correnti).

Il sistema è basato sul recente kernel di Linux, GCC usato è della versione 6.2.

Il problema è che la query DB può durare, e quindi il thread dell'applicazione sta dormendo ei client con attività che richiedono query molto più veloci devono attendere un thread che in realtà non fa nulla.

Sto pensando a diverse possibilità che rendono l'applicazione asincrona ad un certo punto. Il problema è nelle dimensioni e nell'età dell'applicazione: non trovo alcun modo per trovare il tempo di riscrivere completamente ciascun "servizio" per supportare un modello asincrono (come gli oggetti FSM in grado di memorizzare il loro stato mentre aspettano che DB risponda e così in grado di essere spostato dallo stack in un archivio). Eppure ogni "servizio" è una classe stessa con una funzione che chiama la funzione DB (sempre uguale) ad alcuni / pochi punti / s all'interno, quindi tutto lo stato di elaborazione è nello stack (all'interno di queste funzioni di override), nessun membro della classe che può essere memorizzato esiste, e come detto sopra riscrivendolo per archiviare qualcosa all'interno dell'oggetto "servizio" per consentire la continuazione usando le tecniche di C ++ dirette (ne so :-)) è un lavoro semestrale al suo meglio.

L'ultima idea era di fornire ogni thread con stack personalizzato usando pthread_attr_setstack (), e manipolare questi dati manualmente dopo la chiamata alla funzione DB (cioè la connessione DB (socket) ei dati dello stack possono aspettare in qualche coda, mentre il thread corrente può passare a più alto stack address (supponendo che lo stack x86 cresca verso il basso)) ripristinandolo dalla memoria e impostando il puntatore dello stack sul posto appropriato (asm esp ed ecc.). Mentre manipolare i dati dello stack non sembra essere un problema (al momento), non so come ripristinare in blocco altri preziosi registri della CPU e possibilmente strutture specifiche del thread del sistema operativo, per consentire la continuazione senza problemi da qualche indirizzo stack, ho ragione che il ripristino della memoria dello stack e il puntatore dello stack non sono sufficienti per continuare l'esecuzione?

Sto cercando alcune informazioni su come questi problemi possano essere risolti e se una mia idea può essere realizzata. Qualsiasi link è apprezzato.

Un'altra idea è quella di avere un grande pool di thread in cui la maggior parte di loro è in letargo. Se il sistema è in grado di gestire normalmente 128 thread simultanei (128 core fisici della CPU), possiamo creare 1280 thread, ma ci dovrebbe essere un programma che consentirà di eseguire solo 128 nello stesso momento, quindi se 1279 thread sono stati bloccati durante l'attesa per la risposta del DB, la successiva richiesta dell'utente verrà elaborata nel thread # 1280 e, se quel thread non è stato bloccato ancora un'ulteriore richiesta può essere elaborata in un altro thread libero da, questo continuerà mentre non otterremo 128 thread in esecuzione. Se la risposta al DB è stata "epolled" con successo, possiamo svegliarci in attesa di questo thread di risposta. Questo modello non è completamente asincrono, poiché nel peggiore scenario tutti i 1280 thread dormiranno in attesa del DB, ma fornirà l'opportunità di avere 10 richieste DB in sospeso.

    
posta Anton Lantcevich 16.05.2017 - 22:31
fonte

3 risposte

2

C'è più di un modo per aggiungere asincronismo. Hai esplorato un'opzione, per rendere l'applicazione a thread singolo più asincrona. Forse c'è un'altra opzione, per creare un'applicazione wrapper che chiama più copie dell'applicazione originale.

Qui presumo che in qualche modo l'applicazione originale abbia un'API o che tu possa creare un'API, in modo che tu possa eseguire quell'applicazione senza alcuna interfaccia utente. L'utente quindi effettua una richiesta, la richiesta viene passata a un'istanza dell'applicazione utilizzando la comunicazione tra processi e l'applicazione wrapper viene riattivata in esecuzione. Quando il risultato è calcolato, l'applicazione wrapper mostra il risultato.

Se durante l'attesa della risposta, arriva un'altra richiesta, manterrai un "pool di processi dell'applicazione", costituito da un numero limitato di istanze del processo di applicazione originale. La richiesta successiva passa alla successiva istanza nel pool che non è occupata. E così via. Le istanze possono essere avviate dinamicamente.

    
risposta data 17.05.2017 - 03:00
fonte
1

A seconda della configurazione e dei requisiti, se le query sono principalmente letture e non molte scritture (come un sistema di reporting), potresti essere in grado di replicare i dati in un database che supporta le chiamate SQL da più client senza stesse limitazioni. L'unico thread DB nell'applicazione di database corrente viene semplicemente utilizzato per estrarre i dati e aggiornare il proprio DB che verrà interrogato dai client.

Nel mio caso per un problema simile, era un database IBM DB2 con restrizioni, quindi l'idea era di replicare su un database MySQL usando un'applicazione Java personalizzata per leggere regolarmente da DB2 e scrivere nel database MySQL che potremmo interrogare senza limitazioni.

    
risposta data 18.05.2017 - 02:16
fonte
0

IMHO, se il codice è troppo cattivo per essere refactored in un comportamento asincrono, non c'è speranza che possa essere refactored in uno threaded. Quindi le opzioni disponibili sono:

  1. Aggiungi un front-end per avviare un nuovo processo per ogni richiesta pesante.
  2. Dati del database della cache.
  3. Mordere il proiettile e rifattorizzare il codice in un comportamento asincrono.
risposta data 18.05.2017 - 12:51
fonte

Leggi altre domande sui tag