Newsgroup: it.comp.lang.delphi
Titolo: Applicazione Multi-thread

Ciao a tutti!
Ho realizzato un'applicazione che tramite dei threads simultanei deve
elaborare i record di un DB. Avrei bisogno di un consiglio sulla
tecnica da adottare per DB con almeno 1 milione di record.
Se il DB avesse al massimo 100.000 record allora avrei passato ad ogni
thread una lista coi record da elaborare.
Siccome il DB ha milioni di record, non mi pare il caso di passare
delle liste con migliaia o milioni di elementi ad ogni thread !
Quindi ho pensato di passare ad ogni thread un "range", cioè il numero
del primo e dell'ultimo record che esso può accedere.
La mia domanda è: a livello di performance è preferibile che ogni
thread lavori su una lista di elementi (che ovviamente si trova in
memoria) oppure che ogni thread acceda continuamente al DB come detto
sopra??
Preciso che il numero di thread solitamente varia da 10 ad un massimo
di 50.
Grazie mille!

 Grazie mille!
Prego, ma ora per favore... spiega meglio.
Ciao,
Andrea

Forse ti sembrerà strano, ma è proprio così. Ho una tabella di un DB
con alcuni milioni di record, i quali devono essere tutti esaminati...
Quindi, piuttosto che passare un lista ad ogni thread ho pensato di
passare un "range" come detto prima, e fare accedere ogni thread al DB
in base al suo range di azione. Però credo che anche questa scelta
presenti alcuni inconvenienti. In questo modo non avrò problemi di
memoria ma avrò problemi di tempo di ricerca, perchè quando un thread
deve accedere ai record del suo range occorrerà un certo tempo per
giungere a tali record...

sopra??
E' preferibile la prima strada, ma ovviamente su una macchina a
singolo processore, avere 50 thread significa ammazzare la macchina.
Non č che aumentando il numero di thread aumenti le performance.
In generale, avere piů thread di quanti processori sono installati,
significa comunque avere performance peggiori.

delle query[...]
Non credo sia quello il punto, non sta parlando di query, sta parlando
di tabelle del proprio DB.  Se la tabella ha 1 milione di record e
vuoi elaborarli tutti, non puoi "ridurre" alcunché.

Se ho capito bene mi consigli quindi di passare ad ogni thread una
lista dei record, anzicchè un range...

 giungere a tali record...
Ti scoccia molto spiegare un pò il tipo di DB e che struttura ha?
Magari la soluzione è lì :-)
Andrea

 vuoi elaborarli tutti, non puoi "ridurre" alcunché.
Il tipo di discorso che faccio io č che magari ogni thread potrebbe
aprire una sua query specifica(qualora sia possibile una cosa di
questo tipo) e fargli fare le elaborazioni dovute, quindi senza
avere un meccanismo "globale" ma tanti meccanismi locali.
Insomma una roba tipo:
for I := 0 to ListaParametri.Count -1 do
begin
   TMyThread.Create(CreaQuery(ListaParametri.Items[ I ]));
end;
una roba di questo tipo...
Ciao,
Andrea

aprire una sua query specifica[...]
Questo serve a portare in parallelo l'elaborazione dei dati, ma non
aumenta di certo le performance.

lista dei record, anzicchč un range...
Se č per questo, ti sconsiglio proprio di usare piů thread.

 aumenta di certo le performance.
Se i thread vengono terminati mano a mano che hanno finito le loro
quote di dati, tipo con un'impostazione "FreeOnTerminate := True"
credo che un guadagno, anche solo piccolo, ci sia... e se i dati
sono così tanti, magari un piccolo guadagno di qui ed uno di là
finisce per essere sensibile.
Ciao,
Andrea

credo che un guadagno, anche solo piccolo, ci sia...
Non c'è nessun "guadagno".

Stavo pensando ad una tecnica di questo tipo:
piuttosto che passare ad ogni thread un range o una lista da elaborare,
stavo pensando di avviare un thread per ogni record, in modo da non
avere grandi tempi di attesa quando un thread cerca i suoi record.
Avviando un thread per ogni record, e terminando i thread che hanno
finito l'elaborazione, i record riferiti dai thread sono vicini, anzi
sono proprio consecutivi.
Quindi così facendo non dovrei avere lo spreco di memoria dato dalla
tecnica del passaggio di una lista, e non dovrei avere il lungo tempo
di attesa dovuto alla ricerca dei record nel range.
Cosa ne pensate??

avere grandi tempi di attesa quando un thread cerca i suoi record.
Carmelo, ti ostini a pensare che avere più thread significhi
necessariamente aumentare le performance.  Non è affatto così.
Un'applicazione multithread è conveniente, in termini di performance,
se "calza" su hardware adeguato.  Finquando resti su una macchina
monoprocessore, non vai molto lontano.  In generale, finquando usi più
thread di quanti processori hai, le performance non scalano.
Poi, pensare di avere un thread per record, in una prospettiva di
tabelle da milioni di record, è semplicemente folle.

tabelle da milioni di record, è semplicemente folle.
Su questo non ci sono dubbi ^^
-- 
Ore 18.30: premo invio.

molto più veloci che in monothread.
Certo, dipende da qual è il collo di bottiglia.  Forse mi sono
espresso in modo un po' superficiale.  E' ovvio che, se devi
"aspettare" in ogni singola elaborazione, allora il multithread rende
più efficiente l'_intera_ operazione, perché la parallelizza su più
fronti (sfruttando i tempi morti).  Ma, in generale, una sequenza di
operazioni, resa multithread, è solo parallela, non più veloce.  E'
più veloce se, invece, c'è un hardware sotto su cui smistare i vari
thread.

Ragazzi, scusatemi ma si sta andando fuori tema e non avete risposto
alla mia domanda. Non voglio sapere se usare il multi-threading o no,
perchè questo è già una certezza. Vorrei sapere quale tecnica mi
consigliate per gestire in modo ottimale questa situazione, in cui ci
sono milioni di record i quali vanno elaborati uno per uno, mandando il
risultato via rete...

alla mia domanda. 
La risposta alla tua domanda l'hai avuta molto tempo fa.
Il fatto che tu non capisca ciň che gli altri scrivono, non vuol
necessariamente dire che essi siano fuori tema.

 wrote:

Non è che ti se prodigato di informazioni però ^^
Che Database usi?
Com'è strutturata la (le) tabella che devi elaborare?
Il record elaborato va eliminato dalla tabella?
Qual'è la chiave primaria?
Il server è mono processore o multiprocessore?
Sistema operativo?
Versione di Delphi?
(le ultime 2 domande possono sembrare stupide ma non lo sono)
Tutte queste cose possono far propendere verso una soluzione o
un'altra.


- DB Access
- Tabella con 1 solo campo, che è la chiave primaria, di tipo testo
- Il record elaborato non va eliminato, va solo letto, e dopo essere
stato elaborato si deve inviare una informazione via internet
- Sistema monoprocessore con Windows



Non ho esperienza con Access.
Presumo che il vero collo di bottiglia sia l'invio dei dati su
internet.
Una soluzione che potresti vedere se funziona è questa (non
semplicissima):
- una thread si occupa di leggere N record che "spalma" su un certo
numero di liste.
- N thread secondari (per esperienza mai più di 4 su un
monoprocessore) si prendono carico di una delle liste a testa ed
elaborano i dati.
Una volta che tutti i thread hanno elaborato i loro dati, il primo
thread legge altri N record e così via.
La difficoltà di questo sistema sta nella sincronizzazione del tutto.
Il primo thread deve inviare una notifica ai sotto-thread per iniziare
l'elaborazione e questi devono notificare il thread primario quando
hanno finito.
Per questo genere di operazione una buona soluzione è l'uso di eventi
(SetEvent) e compagnia cantante.
Comunque il tutto, se scritto come dio comanda, ti farà guadagnare in
prestazioni e, cosa da non disprezzare, può anche essere divertente da
scrivere ;-)
Dimenticavo. 
Utilizza FastMM per la memoria, avrai dei notevoli miglioramenti delle
perfomance.


Tempo fa ho lavorato con un DB Access abbastanza grande, e avevo visto
delle lunghe attese nella ricerca di un record. Però se ricordo bene,
quando punto direttamente ad un record, senza effettuare alcuna ricerca
ma indicandone la posizione, l'accesso è istantaneo. Quindi credo che
la soluzione del "range" che avevo pensato potrebbe andare bene.
Il concetto del range è questo: ogni record può accedere al DB dal
record x al record x+n, dove x varia da thread a thread.
Data per buona questa scelta, si pone il problema del come poter
chiudere il programma e ripartire in un secondo momento. Per risolvere
questa questione, ho pensato di ridurre il "range" al minimo, cioè a
1. In modo che ogni thread acceda ad un solo record. Così quando
dovrò far ripartire l'elaborazione sarà semplicissimo trovare il
punto da cui far ripartire l'elaborazione.

(SetEvent) e compagnia cantante.
Meglio usare i messaggi.

Meglio usare i messaggi.
Perché? (domanda non polemica :)  )


Perché? (domanda non polemica :)  )
Perché gli eventi servono a sincronizzare, non a notificare.
Se si tratta di "notificare", far parlare i thread tra loro, laddove
non sia richiesta una sequenza precisa nella comunicazione, è
necessario usare i messaggi, che sono asincroni.  L'uso di un evento
significa rendere bloccante la comunicazione.

[...]In modo che ogni thread acceda ad un solo record.[...]
Quindi, fammi capire, col crescere a piacere di quel n, fai crescere
conseguentemente il numero di record ? 
Tu non sai che stai facendo.  Auguri.

punto da cui far ripartire l'elaborazione.
Scusa, ma a questo punto vuoi dirmi che crei un thread per accedere ad
un *singolo* record?
Il problema di riprendere da un dato record non mi sembra
insormontabile, mentre la soluzione di utilizzare il singolo record mi
pare, consentimi, quantomeno bizzarra.
