Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Opera Neon: il browser AI agentico di nuova generazione
Opera Neon: il browser AI agentico di nuova generazione
Abbiamo provato il nuovo web browser con intelligenza artificiale della serie Opera accessibile tramite abbonamento. Ecco le nostre prime impressioni sulle funzionalità di Opera Neon basate su AI e come funzionano
Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Con la prima rete 5G Standalone attiva in Italia, WINDTRE compie un passo decisivo verso un modello di connettività intelligente che abilita scenari avanzati per imprese e pubbliche amministrazioni, trasformando la rete da infrastruttura a piattaforma per servizi a valore aggiunto
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro punta a diventare uno dei riferimenti assoluti nel segmento dei camera phone di fascia alta. Con un teleobiettivo Hasselblad da 200 MP, una batteria al silicio-carbonio da 7500 mAh e un display da 6,78 pollici con cornici ultra ridotte, il nuovo flagship non teme confronti con la concorrenza, e non solo nel comparto fotografico mobile. La dotazione tecnica include il processore MediaTek Dimensity 9500, certificazione IP69 e un sistema di ricarica rapida a 80W
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 14-05-2014, 11:34   #1
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
[Java] Thred e similuazione di acquisizione/computazione dati da sensore

Salve a tutti,
ho il seguente problema da cui non riesco a venirne fuori, provo a descriverlo mediante un toy example:

Mettiamo il caso che io ho N file csv, ogni file simula i dati acquisiti da un sensore. Ad esempio se il sensore fosse una stazione meteo potremmo dire che il file csv contiene al suo interno le seguenti colonne:

timestamp - temperatura - umidità

Ora la cadenza con cui i sensori inviano le informazioni sono randomiche per ogni sensore, questo significa che i file csv possono essere di diversa lunghezza e che i timestamp dei vari file csv non sono allineati.

Io con questi file dovrei simulare un acquisizione online delle informazioni dal sensore, ovvero far finta che ci sia uno streaming di dati aperto con ogni sensore, ed il sensore quando vuole lui mi manda dei dati.

Fin qui sarebbe facile, ovvero potrei creare N thread, uno per sensore, ognuno che legge una riga alla volta il csv di un sensore. Il problema però è più complicato, io con i dati arrivati dai sensori devo fare delle operaizoni quindi ogni qualvolta mi arriva un dato da uno qualsiasi dei sensori io devo lanciare una funzione che mi esegue dei conteggi.

Quindi l'esempio potrebbe essere del tipo:
Sono in ascolto su N sensori, ed ho una struttura dati con dei conteggi che è comune per tutti i sensori. Appena mi arriva un osservazione da uno qualsiasi dei sensori devo lanciare una funzione che mi aggiorna i conteggi (che ripeto sono in comune su tutti i sensori) e che se si verifica una certa condizione mettiamo che chiama un ulteriore funzione.

Come potrei fare tutto questo?

Vi ringrazio in anticipo per l'aiuto,
guylmaster.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 11:44   #2
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
La parte più complessa nel tuo problema è la sincornizzazione. Java mette a disposizione un meccanismo molto semplice per far si che due o più thread accedano uno per volta ad una risorsa, basta utilizzare un blocco synchronized.
Se l'elaborazione è veramente breve puoi richiamarla dai thread stessi, altrimenti conviene avere un thread dedicato da tenere in pausa ed attivare quando arriva un dato. A questo punto dovresti decidere cosa fare se arriva un dato mentre è già in corso un'elaborazione per decidere come implementare il tutto.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 12:01   #3
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
La parte più complessa nel tuo problema è la sincornizzazione. Java mette a disposizione un meccanismo molto semplice per far si che due o più thread accedano uno per volta ad una risorsa, basta utilizzare un blocco synchronized.
Se l'elaborazione è veramente breve puoi richiamarla dai thread stessi, altrimenti conviene avere un thread dedicato da tenere in pausa ed attivare quando arriva un dato. A questo punto dovresti decidere cosa fare se arriva un dato mentre è già in corso un'elaborazione per decidere come implementare il tutto.

Il problema è un pò più complesso, non devo solo sincronizzare l'accesso alla struttura dati dei conteggi. Ti faccio un esempio pratico:

Se ho due sensori, ognuno con il proprio file csv:

Codice:
Csv1:
18:00 - low  - low
19:00 - low  - high

Csv2
18:03 - high - low
Ho bisogno di leggere prima l'osservazione alle 18:00 di csv1 e aggiornare i conti, poi quella alle 18:03 e aggiornare i conti e poi di nuovo alle 19:00 del file csv1 ed aggiornare i conti. Se aggiornado i conti si verifica una determianta condizione devo lanciare una determinata routine.

Se facessi un thread per ogni sensore che legge il file CSV non saprei come dirgli di leggere in ordine temporale sopra tutti i sensori.

In pratica ogni thread legge le osservazioni una per volta dal proprio file CSV in maniera sequenziale, ma in realtà il thread che ha a disposizione l'osservazione con il time stamp più recente ha diritto di eseguire i conteggi e non solo, gli altri devono rimanere in pausa in attesa che finisca per poi poter lanciare loro l'aggiornamento dei conteggi sempre in ordine di osservazione più recente. Questo perchè i conteggi devono essere ricalcolati per ogni osservazione.

Ultima modifica di guylmaster : 14-05-2014 alle 12:05.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 12:45   #4
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Ho capito, comunque questo è un problema che può verificarsi solo in fase di test, perché i veri sensori inviano (spero) i dati appena sono disponibili, quindi questi arriveranno naturalmente ordinati per timestamp.
Certo potrebbe verificarsi che due sensori inviino i propri dati a distanza di pochi microsecondi e che i thread se ne accorgano in ordine inverso, in questo caso - se per te conta anche il microsecondo - ha senso preoccuparsi.

Quindi, se non ti interessa un precisione da orologio atomico ma vuoi solo risolvere il problema in fase di test, basta che le righe dei CSV vengano lette da un thread separato che le mette in ordine e poi informa di volta in volta il thread opportuno.

Se invece vuoi gestire anche il caso di cui ti ho parlato prima, devi inserire i dati ricevuti in una coda a priorità e definire una "vecchiaia" minima prima di elaborare i dati. Non esiste infatti alcuna sfera di cristallo che consenta di sapere se in futuro arriverà un dato che riguarda un avvenimento precedente, bisogna per forza stabilire un margine di tolleranza e sperare che non venga superato.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 13:58   #5
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Ho capito, comunque questo è un problema che può verificarsi solo in fase di test, perché i veri sensori inviano (spero) i dati appena sono disponibili, quindi questi arriveranno naturalmente ordinati per timestamp.
Certo potrebbe verificarsi che due sensori inviino i propri dati a distanza di pochi microsecondi e che i thread se ne accorgano in ordine inverso, in questo caso - se per te conta anche il microsecondo - ha senso preoccuparsi.

Quindi, se non ti interessa un precisione da orologio atomico ma vuoi solo risolvere il problema in fase di test, basta che le righe dei CSV vengano lette da un thread separato che le mette in ordine e poi informa di volta in volta il thread opportuno.

Se invece vuoi gestire anche il caso di cui ti ho parlato prima, devi inserire i dati ricevuti in una coda a priorità e definire una "vecchiaia" minima prima di elaborare i dati. Non esiste infatti alcuna sfera di cristallo che consenta di sapere se in futuro arriverà un dato che riguarda un avvenimento precedente, bisogna per forza stabilire un margine di tolleranza e sperare che non venga superato.
Si sono in fase di test, ma visto che il mio scopo è creare un modello matematico (che poi chi vorrà potrà utilizzarsi lui per quello che vuole) in realtà non ci sarà mai una fase successiva di funzionamento vero e proprio (almeno da parte mia). Quindi poi dipenderà dal dominio di applicazione che uno dovrà andarsi a studiare bene i ritardi eccetera.

Ora dato che parliamo di calcoli abbastanza pesanti mi è stato chiesto di sviluppare il tutto su più thread, perchè l'idea è che in futuro questa cosa potrebbe evolvere come "un server per ogni sensore" o qualcosa di simile.

Ritornando ai multi-thread però mi è sorto in dubbio. Anche se gestisco l'ordinamento delle osservazioni con una coda con priorità (spero esista già una sua implementazione in java) in realtà visto che i conteggi vanno fatti un osservazione per volta, e visto che per fare i conteggi io devo bloccare l'accesso alla struttura dati, non ritorniamo di nuovo al caso del sequenziale?

Cioè Thread1 riceve un osservazione, inizia i calcoli e blocca la risorsa conteggi, thread2 nel mentre riceve un osservazione ma deve aspettare che i conteggi vengano sbloccati. A questo punto ritorna tutto ad essere sequenziale, no?
Potrei semplicemente leggere una riga per volta da ogni CSV e mettere le osservazioni in una coda con priorità. Poi elaboro tutte le osservazioni nella coda con priorità e solo DOPO averle elaborate tutte passo a leggere un ulteriore riga dai csv.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 14:08   #6
ingframin
Senior Member
 
L'Avatar di ingframin
 
Iscritto dal: Apr 2010
Città: Leuven
Messaggi: 667
Ti conviene raccogliere i dati in arrivo in una coda, quando hai una coda completa fai la tua elaborazione (svuoti la coda) e riparti da capo.
Un altra alternativa e' calcolare ogni volta che ti arriva un dato e correggere il conteggio quando arrivano gli altri.
Non puoi predire il futuro, quindi a un certo punto dovrai fare il tuo calcolo senza aspettare troppo a lungo.

EDIT: non avevo letto l'ultimo post, e' esattamente quello che intendevo io... e' la vecchiaia che mi frega
__________________
L'elettronica digitale non esiste, è solo elettrotecnica con interruttori piccoli!
ingframin è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 14:21   #7
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da ingframin Guarda i messaggi
Ti conviene raccogliere i dati in arrivo in una coda, quando hai una coda completa fai la tua elaborazione (svuoti la coda) e riparti da capo.
Un altra alternativa e' calcolare ogni volta che ti arriva un dato e correggere il conteggio quando arrivano gli altri.
Non puoi predire il futuro, quindi a un certo punto dovrai fare il tuo calcolo senza aspettare troppo a lungo.

EDIT: non avevo letto l'ultimo post, e' esattamente quello che intendevo io... e' la vecchiaia che mi frega

Ma quindi, considerado che sto leggendo da N file csv, mi conviene leggere una riga per ogni csv, le butto dentro alla coda con priorità, e poi le estraggo da li ordinate per tempo.

La coda con priorità sarà quindi una coda di priorità di Mia_classe_personalizzata, che conterrà all'interno le variabili "timestamp" ed altre. E la priorità sarà data a quella con il timestamp più basso (il timestmap è un double).

Ultima modifica di guylmaster : 14-05-2014 alle 14:31.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 14:39   #8
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Dipende, se vuoi solo dimostrare l'elaborazione non c'è bisogno di thread e code, basta ordinare i dati e farli elaborare in sequenza. Se invece ti interessa implementare un'applicazione che sia già predisposta al collegamento con i sensori, allora dovrai prendere qualche accorgimento in più.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 15:10   #9
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Dipende, se vuoi solo dimostrare l'elaborazione non c'è bisogno di thread e code, basta ordinare i dati e farli elaborare in sequenza. Se invece ti interessa implementare un'applicazione che sia già predisposta al collegamento con i sensori, allora dovrai prendere qualche accorgimento in più.
Mettiamo il caso che voglio farlo il più realistico possibile ed il più "parallelizzato" possibile (quindi se servono i thread mettiamo i thread).

Teniamo conto che:

Al posto dei sensori abbiamo un csv per ogni sensore, e all'interno di un file csv le osservazioni del singolo sensore sono ordinate dalla più vecchia alla più recente;

Ho una struttura dati Conteggi, che è comune per tutti i sensori;

Ho una funzione "effettuaConteggi", che deve essere richiamata per ogni osservazione che arriva e che ha bisogno per effettuare i conteggi sia dell'osservazione attuale che dell'osservazione precedente del medesimo sensore (perchè vogliamo contare i cambi di stato e il tempo di permanenza nei vari stati). Oltre che ovviamente della struttura dati Conteggi;

Tu come lo svilupperesti? ti verrebbe da buttarmi giù un minimo di pseudocodice per capirci meglio?
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 14-05-2014, 16:47   #10
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
La risposta sta venendo un po' lunga, invio la prima parte.

Nell'ottica di realizzare un'applicazione quanto più possibile vicina all'uso pratico, dovresti prima di tutto definire bene come vengono letti i dati dai sensori. Mi rendo conto che questo potrebbe essere un aspetto del tutto sconosciuto al momento, quindi ti faccio questa proposta:
definisci una classe astratta Valore che contiene il campo timestamp e derivane una classe per ogni tipologia di sensore contenente altri N campi associati ai valori restituiti dal sensore, ad esempio:
Codice:
abstract class Valore {
  public long timestamp;
}

class ValoreStazioneMeteo extends Valore {
  public double temperatura;
  public double umidita;
}
definisci una classe astratta "Sensore" che presenta un metodo "Valore read()". Tale metodo è sincrono, ovvero, una volta invocato si blocca fino a quando il dato diventa disponibile. Quando il dato è disponibile il metodo restituisce il valore letto e il timestamp corrispondente.
Codice:
abstract class Sensore {
  public abstract Valore read();
}
A questo punto potrai implementare la classe SensoreCsv che estende la classe Sensore (presenta quindi il metodo read).
L'implementazione di questa classe potrebbe essere questa:
Codice:
abstract class SensoreCsv extends Sensore {
  private SynchronousQueue<Valore> coda = new SynchronousQueue<Valore>();
  protected BufferedReader br = null;
  
  @Override
  public Valore read() {
    return coda.take();
  }
  
  public void setFile(String filename) {
    br = new BufferedReader(new FileReader(filename));
  }
  
  abstract Valore readCsv();
  
  void write(Valore val) {
    coda.put(val);
  }
}
E finalmente:
Codice:
class SensoreStazioneMeteoCsv extends SensoreCsv {
  @Override
  ValoreStazioneMeteo readCsv() {
    String line = br.readLine();
    if (line == null) return null;
    ValoreStazioneMeteo val = new ValoreStazioneMeteo();
    //facciamo il parsing della riga e popoliamo i campi di val
    return val;
  }
}
Un thread dedicato si occuperà della lettura del csv:
Codice:
class CsvReader implements Runnable {
  private HashMap<SensoreCsv,Valore> valoriSensori = new HashMap<Sensore,Valore>();
  
  CsvReader() {
    //Popoliamo l'attributo "valoriSensori"
    SensoreCsv sensore = new SensoreStazioneMeteoCsv();
    sensore.setFile("file.csv");
    Valore val = sensore.readCsv();
    valoriSensori.put(sensore, valore);
  }
  
  public void run() {
    Set<Map.Entry<SensoreCsv,Valore>> setVS = valoriSensori.entrySet();
    boolean done;
    do {
      //EDIT se non mettiamo questa riga il ciclo non termina mai:
      done = true;
      long minTimestamp = Long.MAX_VALUE;
      //Cerchiamo il sensore con il timestamp minore
      SensoreCsv prossimoSensore = null;
      for (Map.Entry<SensoreCsv,Valore> valoreSensore : setVS) {
        Valore val = valoreSensore.getValue();
        if (val != null && val.timestamp < minTimestamp) {
          minTimestamp = val.timestamp;
          prossimoSensore = valoreSensore.getKey();
        }
      }
      //Se c'era almeno un dato disponibile
      if (prossimoSensore != null) {
        Valore val = valoriSensori.get(prossimoSensore); //Otteniamo il Valore
        prossimoSensore.write(val); //Avvisiamo il sensore che deve pubblicare il dato
        Valore newVal = prossimoSensore.readCsv();
        valoriSensori.put(prossimoSensore, newVal);
        done = false;
      }
    } while (!done);
  }
}
A questo punto, salvo mie immancabili imprecisioni, dovresti avere un'interfaccia che simula egregiamente dei sensori ad interrogazione sincrona, non resta che sviluppare l'applicazione che deve interrogarli (continuerò domani).

Ultima modifica di Daniels118 : 14-05-2014 alle 16:51.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 00:27   #11
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
La risposta sta venendo un po' lunga, invio la prima parte.

Nell'ottica di realizzare un'applicazione quanto più possibile vicina all'uso pratico, dovresti prima di tutto definire bene come vengono letti i dati dai sensori. Mi rendo conto che questo potrebbe essere un aspetto del tutto sconosciuto al momento, quindi ti faccio questa proposta:
definisci una classe astratta Valore che contiene il campo timestamp e derivane una classe per ogni tipologia di sensore contenente altri N campi associati ai valori restituiti dal sensore, ad esempio:
Codice:
abstract class Valore {
  public long timestamp;
}

class ValoreStazioneMeteo extends Valore {
  public double temperatura;
  public double umidita;
}
definisci una classe astratta "Sensore" che presenta un metodo "Valore read()". Tale metodo è sincrono, ovvero, una volta invocato si blocca fino a quando il dato diventa disponibile. Quando il dato è disponibile il metodo restituisce il valore letto e il timestamp corrispondente.
Codice:
abstract class Sensore {
  public abstract Valore read();
}
A questo punto potrai implementare la classe SensoreCsv che estende la classe Sensore (presenta quindi il metodo read).
L'implementazione di questa classe potrebbe essere questa:
Codice:
abstract class SensoreCsv extends Sensore {
  private SynchronousQueue<Valore> coda = new SynchronousQueue<Valore>();
  protected BufferedReader br = null;
  
  @Override
  public Valore read() {
    return coda.take();
  }
  
  public void setFile(String filename) {
    br = new BufferedReader(new FileReader(filename));
  }
  
  abstract Valore readCsv();
  
  void write(Valore val) {
    coda.put(val);
  }
}
E finalmente:
Codice:
class SensoreStazioneMeteoCsv extends SensoreCsv {
  @Override
  ValoreStazioneMeteo readCsv() {
    String line = br.readLine();
    if (line == null) return null;
    ValoreStazioneMeteo val = new ValoreStazioneMeteo();
    //facciamo il parsing della riga e popoliamo i campi di val
    return val;
  }
}
Un thread dedicato si occuperà della lettura del csv:
Codice:
class CsvReader implements Runnable {
  private HashMap<SensoreCsv,Valore> valoriSensori = new HashMap<Sensore,Valore>();
  
  CsvReader() {
    //Popoliamo l'attributo "valoriSensori"
    SensoreCsv sensore = new SensoreStazioneMeteoCsv();
    sensore.setFile("file.csv");
    Valore val = sensore.readCsv();
    valoriSensori.put(sensore, valore);
  }
  
  public void run() {
    Set<Map.Entry<SensoreCsv,Valore>> setVS = valoriSensori.entrySet();
    boolean done;
    do {
      //EDIT se non mettiamo questa riga il ciclo non termina mai:
      done = true;
      long minTimestamp = Long.MAX_VALUE;
      //Cerchiamo il sensore con il timestamp minore
      SensoreCsv prossimoSensore = null;
      for (Map.Entry<SensoreCsv,Valore> valoreSensore : setVS) {
        Valore val = valoreSensore.getValue();
        if (val != null && val.timestamp < minTimestamp) {
          minTimestamp = val.timestamp;
          prossimoSensore = valoreSensore.getKey();
        }
      }
      //Se c'era almeno un dato disponibile
      if (prossimoSensore != null) {
        Valore val = valoriSensori.get(prossimoSensore); //Otteniamo il Valore
        prossimoSensore.write(val); //Avvisiamo il sensore che deve pubblicare il dato
        Valore newVal = prossimoSensore.readCsv();
        valoriSensori.put(prossimoSensore, newVal);
        done = false;
      }
    } while (!done);
  }
}
A questo punto, salvo mie immancabili imprecisioni, dovresti avere un'interfaccia che simula egregiamente dei sensori ad interrogazione sincrona, non resta che sviluppare l'applicazione che deve interrogarli (continuerò domani).
Mi sono accorto di un problema, che effettiamente era sfuggito nei miei test anche a me:

Se io leggo un osservazione per sensore e prendo la più recente è un problema, vediamolo con un esempio:

CSV1:
8:00 - temperature - umidità
8:10 - temparatura - umidità

CSV2:
8:20 - temperature - umidità
9:00....

Cosi facendo farò 8:00 dal primo sensore e 8:20 dal secondo sensore. Poi però nel primo sensore ho 8:10 come seconda lettura. Quindi come si fa?
Metti caso che un sensore fa tantissime osservazioni ravvicinate e l'altro no come faccio a risolvere questo problema? dovrei leggere tutte le osservazioni, di tutti i csv, e prendere da li la più vecchia? Ma qui parliamo di avere anche 400.000 e più osservazioni rischiamo che manco ci entrano tutte e finiamo la memoria nei casi peggiori.

Comunque grazie mille a tutti per l'aiuto che mi state dando

Ultima modifica di guylmaster : 15-05-2014 alle 00:29.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 08:39   #12
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Rivedi il metodo run che ho realizzato nel mio precedente post, è un'implementazione di un algoritmo di merge che serve a risolvere il problema al quale accennavi, se vuoi ulteriori dettagli sul funzionamento vedi qui: Merge algorithm.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 10:23   #13
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Forse può fare al caso tuo una coda di priorità boccante: java.util.concurrent.PriorityBlockingQueue (le librerie Java hanno già un sacco di pappa pronta all'uso, testata e ben funzionante, non serve ogni volta reinventare la ruota).

I thread-sensori tentano di schiaffare dati nella coda.
C'è un thread lettore (ma possono essere anche più di uno) che tenta di estrarre i dati dalla coda.

La coda è bloccante: finchè è piena (stabilisci tu quanto grande farla) i thread-sensori restano in attesa che si liberino dei posti, e finchè è vuota il thread lettore resta in attesa del primo dato disponibile.

La coda è una coda di priorità: ogni elemento infilato nella coda viene riordinato nella stessa in base ad una politica di priorità (stabilisci tu il criterio, mediante un Comparator, per intenderci).

---

Questo dopo aver letto al volo la discussione e al netto della mia memoria; sono almeno sue anni che non programmo praticamente più...
Comunque prima di progettare l'implementazione di una soluzione usando un certo strumento, sarebbe il caso di andare a studiarsi quello strumento (prendila come un consiglio, non come una critica, non vuole esserlo! E' che è proprio questa la causa dei tuoi dubbi, secondo me).
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 10:40   #14
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2780
Quote:
Originariamente inviato da banryu79 Guarda i messaggi
Questo dopo aver letto al volo la discussione e al netto della mia memoria; sono almeno sue anni che non programmo praticamente più...
Posso chiederti di cosa ti occupi ora? Ti ho sempre letto con piacere e mi dispiacerebbe non leggerti più...
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 12:27   #15
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Rivedi il metodo run che ho realizzato nel mio precedente post, è un'implementazione di un algoritmo di merge che serve a risolvere il problema al quale accennavi, se vuoi ulteriori dettagli sul funzionamento vedi qui: Merge algorithm.
Ammetto che volevo riadattare il tutto all'utilizzo delle code di priorità ma ho fatto casino.

Io prima, per andare in errore, prendevo un valore per ogni sensore e poi me li computavo in ordine timestamp crescente. Solo dopo aver computato tutti i valori rileggevo dai sensori. Questo faceva si che avevo valori non allineati.

Se invece prendo una lettura per sensore, prendo il valore del sensore più piccolo e di quel sensore di cui ho preso il valore più piccolo leggo subito il successivo valore, dovrei evitare il problema.
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 12:29   #16
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da banryu79 Guarda i messaggi
Forse può fare al caso tuo una coda di priorità boccante: java.util.concurrent.PriorityBlockingQueue (le librerie Java hanno già un sacco di pappa pronta all'uso, testata e ben funzionante, non serve ogni volta reinventare la ruota).

I thread-sensori tentano di schiaffare dati nella coda.
C'è un thread lettore (ma possono essere anche più di uno) che tenta di estrarre i dati dalla coda.

La coda è bloccante: finchè è piena (stabilisci tu quanto grande farla) i thread-sensori restano in attesa che si liberino dei posti, e finchè è vuota il thread lettore resta in attesa del primo dato disponibile.

La coda è una coda di priorità: ogni elemento infilato nella coda viene riordinato nella stessa in base ad una politica di priorità (stabilisci tu il criterio, mediante un Comparator, per intenderci).

---

Questo dopo aver letto al volo la discussione e al netto della mia memoria; sono almeno sue anni che non programmo praticamente più...
Comunque prima di progettare l'implementazione di una soluzione usando un certo strumento, sarebbe il caso di andare a studiarsi quello strumento (prendila come un consiglio, non come una critica, non vuole esserlo! E' che è proprio questa la causa dei tuoi dubbi, secondo me).

Io stavo provando questo esempio di SynchronousQueue:

Codice:
package threadTest;


import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueTest 
{
    private SynchronousQueue sq = new SynchronousQueue(true);

    class PutThread implements Runnable 
    {
        public void run() 
        {
            for(int i=0; i <1000; i++)
            {
                try {
                System.out.println("PUT");
                //sq.put("A");
                sq.put("A");
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
            }
        }

    }

    class TakeThread implements Runnable 
    {
        public void run() 
        {
            for(int i=0; i <1000; i++)
            {
                try {
                System.out.println("TAKE");
                System.out.println(sq.take());
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args)
    {
        new Thread((new SynchronousQueueTest()).new PutThread()).start();
        new Thread((new SynchronousQueueTest()).new TakeThread()).start();
    }
}
Il problema è che mio aspettato 1000 PUT e 1000 TAKE alternati, invece stampa un PUT ed un TAKE e rimane in pausa all'infinito. Dove sbaglio?
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 12:41   #17
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
L'errore sta nel fatto che i due thread utilizzano due istanze diverse di SynchronousQueueTest, pertanto fanno riferimento a due code diverse.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 13:20   #18
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Continuiamo da dove ci eravamo fermati ieri.

Definiamo un comparatore per la coda a priorità:
Codice:
class CompTimestampValore implements Comparator<Valore> {
  int compare(Valore o1, Valore o2) {
    if (o1.timestamp < o2.timestamp) return -1;
    if (o1.timestamp > o2.timestamp) return 1;
    return 0;
  }
}
Definiamo quindi una classe capace di leggere i dati dei sensori e comunicarli ad un elaboratore:
Codice:
class SensorReader implements Runnable {
  protected Sensore sensore;
  protected Elaboratore elaboratore;
  
  public setSensore(Sensore sensore) {
    this.sensore = sensore;
  }
  
  public setElaboratore(Elaboratore elaboratore) {
    this.elaboratore = elaboratore;
  }
  
  public void run() {
    while (true) {
      Valore val = sensore.read();
      elaboratore.send(val);
    }
  }
}
Ancora una classe per gestire il delay:
Codice:
class ValoreHolder {
  private Valore valore;
  private long expires;
  
  ValoreHolder(Valore valore, long delay) {
    this.valore = valore;
    Date d = new Date();
    this.expires = d.getTime() + delay;
  }
  
  boolean isOld() {
    Date d = new Date();
    return d.getTime() >= expires;
  }
  
  Valore getValore() {
    return this.valore;
  }
}
Infine definiamo una classe per elaborare i dati:
Codice:
class Elaboratore implements Runnable {
  protected PriorityQueue<ValoreHolder> coda;
  
  public Elaboratore() {
    CompTimestampValore comparatore = new CompTimestampValore();
    this.coda = new PriorityQueue<ValoreHolder>(100, comparatore);
  }
  
  public void bindSensore(sensore) {
    SensorReader reader = new SensorReader();
    reader.setSensore(sensore);
    reader.setElaboratore(this);
    Thread t = new Thread();
    t.start(reader);
  }
  
  public void run() {
    while (true) {
      ValoreHolder holder;
      //Attendiamo che la coda contenga un valore abbastanza vecchio
      while (true) {
        synchronized (coda) {
          holder = coda.peek(); //Leggiamo il valore senza rimuoverlo
        }
        if (holder == null) {
          Thread.sleep(100); //La coda è vuota, aspettiamo un po'
        } else if (holder.isOld()) { //Se il valore è abbastanza vecchio
          synchronized (coda) {
            holder = coda.poll(); //Rimuoviamolo dalla coda
          }
          break;
        }
      }
      Valore val = holder.getValore();
      //Elaboriamo il valore
      
    }
  }
  
  public void send(Valore val) {
    ValoreHolder holder = new ValoreHolder(val, 500);
    synchronized (coda) {
      coda.add(holder);
    }
  }
}
Salvo i soliti errori dovrebbe fare quello che ti serve.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 13:58   #19
guylmaster
Senior Member
 
L'Avatar di guylmaster
 
Iscritto dal: Aug 2002
Messaggi: 2518
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Continuiamo da dove ci eravamo fermati ieri.

Definiamo un comparatore per la coda a priorità:
Codice:
class CompTimestampValore implements Comparator<Valore> {
  int compare(Valore o1, Valore o2) {
    if (o1.timestamp < o2.timestamp) return -1;
    if (o1.timestamp > o2.timestamp) return 1;
    return 0;
  }
}
Definiamo quindi una classe capace di leggere i dati dei sensori e comunicarli ad un elaboratore:
Codice:
class SensorReader implements Runnable {
  protected Sensore sensore;
  protected Elaboratore elaboratore;
  
  public setSensore(Sensore sensore) {
    this.sensore = sensore;
  }
  
  public setElaboratore(Elaboratore elaboratore) {
    this.elaboratore = elaboratore;
  }
  
  public void run() {
    while (true) {
      Valore val = sensore.read();
      elaboratore.send(val);
    }
  }
}
Ancora una classe per gestire il delay:
Codice:
class ValoreHolder {
  private Valore valore;
  private long expires;
  
  ValoreHolder(Valore valore, long delay) {
    this.valore = valore;
    Date d = new Date();
    this.expires = d.getTime() + delay;
  }
  
  boolean isOld() {
    Date d = new Date();
    return d.getTime() >= expires;
  }
  
  Valore getValore() {
    return this.valore;
  }
}
Infine definiamo una classe per elaborare i dati:
Codice:
class Elaboratore implements Runnable {
  protected PriorityQueue<ValoreHolder> coda;
  
  public Elaboratore() {
    CompTimestampValore comparatore = new CompTimestampValore();
    this.coda = new PriorityQueue<ValoreHolder>(100, comparatore);
  }
  
  public void bindSensore(sensore) {
    SensorReader reader = new SensorReader();
    reader.setSensore(sensore);
    reader.setElaboratore(this);
    Thread t = new Thread();
    t.start(reader);
  }
  
  public void run() {
    while (true) {
      ValoreHolder holder;
      //Attendiamo che la coda contenga un valore abbastanza vecchio
      while (true) {
        synchronized (coda) {
          holder = coda.peek(); //Leggiamo il valore senza rimuoverlo
        }
        if (holder == null) {
          Thread.sleep(100); //La coda è vuota, aspettiamo un po'
        } else if (holder.isOld()) { //Se il valore è abbastanza vecchio
          synchronized (coda) {
            holder = coda.poll(); //Rimuoviamolo dalla coda
          }
          break;
        }
      }
      Valore val = holder.getValore();
      //Elaboriamo il valore
      
    }
  }
  
  public void send(Valore val) {
    ValoreHolder holder = new ValoreHolder(val, 500);
    synchronized (coda) {
      coda.add(holder);
    }
  }
}
Salvo i soliti errori dovrebbe fare quello che ti serve.
In pratica con Syncronyzed di una variabile cosa succede? il thread successivo si mette automaticamente in coda e parte solo quando la variabile non è più usata? E se si mette in attesa da solo allora a cosa serve lo sleep? o c'è qualcosa che mi sfugge nel funzionamento di Syncronyzed?

Ho provato a fixare l'esempio SynchronousQueue così:

Codice:
package threadTest;


import java.util.concurrent.SynchronousQueue;
 
public class SynchronousQueueTest 
{
	private static SynchronousQueue sq;
	
	class PutThread implements Runnable 
	{
		SynchronousQueue sq;
		public void run() 
		{
			for(int i=0; i <1000; i++)
			{
				try {
				System.out.println("PUT");
				//sq.put("A");
				sq.put("A");
				} catch (InterruptedException e) {
				e.printStackTrace();
				}
			}
		}
		public PutThread(SynchronousQueue sq) 
		{
			this.sq = sq;
		}
		
	}
	
	class TakeThread implements Runnable 
	{
		SynchronousQueue sq;
		
		public void run() 
		{
			for(int i=0; i <1000; i++)
			{
				try {
				System.out.println("TAKE");
				//System.out.println(sq.take());
				sq.take();
				} catch (InterruptedException e) {
					System.out.println("wait");
				e.printStackTrace();
				}
			}
		}
		public TakeThread(SynchronousQueue sq) 
		{
			this.sq = sq;
		}
	}
		
	public static void main(String[] args)
	{
		SynchronousQueue sq = new SynchronousQueue();
		new Thread((new SynchronousQueueTest()).new PutThread(sq)).start();
		new Thread((new SynchronousQueueTest()).new TakeThread(sq)).start();
	}
}
Però l'output non è del tutto alternato, è di questo genere:

Codice:
PUT
TAKE
TAKE
PUT
PUT
TAKE
TAKE
PUT
Cosa altro sbaglio?
guylmaster è offline   Rispondi citando il messaggio o parte di esso
Old 15-05-2014, 15:21   #20
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
I blocchi synchronized non agiscono su una variabile, ma su un oggetto: è importante fare questa differenza, perché variabili diverse possono puntare allo stesso oggetto.
Se un thread accede ad un blocco synchronized per un dato oggetto, tutti gli altri thread che vogliono accedere ad un blocco synchronized per quello stesso oggetto si mettono in pausa finché il primo thread non esce dal blocco.
Questo costrutto si usa specialmente quando si vuole impedire che un thread legga un oggetto mentre questo viene modificato da un altro thread.
Esistono anche delle classi "thread-safe" i cui metodi sono sincronizzati internamente, però vista la quantità minima di istruzioni da sincronizzare in questa applicazione secondo me conviene fare da se.

Nota che sleep viene richiamato all'esteno del blocco synchronized. Il blocco synchronized serve per evitare di leggere dalla coda mentre un altro thread vi sta scrivendo; se non prendessimo questa precauzione, la lettura potrebbe restituire dati errati. Se la coda è vuota peek() ritorna null, e solo il questo caso viene eseguito sleep(); ciò serve ad evitare un inutile sovraccarico nel caso in cui la coda sia vuota.

Quanto al codice che hai postato, il problema sta nel fatto che la stampa del messaggio TAKE avviene prima della chiamata al rispettivo metodo. Facciamo un esempio:
1) Le code sono vuote
2) PutThread stampa "PUT"
3) PutThread chiama put e si blocca perché la coda è piena
4) TakeThread stampa "TAKE"
5) TakeThread chiama take, trova un valore in coda e ritorna
6) TakeThread stampa "TAKE"
7) TakeThread chiama take e si blocca perchè la coda è vuota
8) PutThread si sblocca perché la coda è vuota
9) PutThread stampa "PUT"
10) PutThread chiama put e si blocca perché la coda è piena
e così via...

Invertendo la chiamata al metodo get e la stampa del relativo messaggio hai la garanzia che questo venga stampato ad operazione avvenuta. Esempio:
1) Le code sono vuote
2) PutThread stampa "PUT"
3) PutThread chiama put e si blocca perché la coda è piena
4) TakeThread chiama take, trova un valore in coda e ritorna
5) TakeThread stampa "TAKE"
6) TakeThread chiama take e si blocca perchè la coda è vuota
7) PutThread si sblocca perché la coda è vuota
8) PutThread stampa "PUT"
9) PutThread chiama put e si blocca perché la coda è piena
10) TakeThread si sblocca perchè la coda è piena
10) TakeThread stampa "TAKE"
e così via...

In realtà anche in questo modo non è garantito che i messaggi vengano stampati in questo ordine perché, sebbene sia molto improbabile, lo switch di contesto potrebbe avvenire proprio tra il ritorno dal metodo e la stampa del messaggio, così:
1) Le code sono vuote
2) PutThread stampa "PUT"
3) PutThread chiama put e si blocca perché la coda è piena
4) TakeThread chiama take, trova un valore in coda e ritorna
5) PutThread si sblocca perché la coda è vuota
6) PutThread stampa "PUT"
7) TakeThread stampa "TAKE"
8) TakeThread chiama take e si blocca perchè la coda è vuota

La soluzione ideale sarebbe quella di mettere la stampa del messaggio direttamente dentro ai metodi sincroni put e take, ma non potendo mettere le mani all'interno di tali metodi l'unica alternativa resta quella di sincronizzare manualmente il codice; in questo caso si potrebbe anche fare a meno della coda ed utilizzare i metodi wait e notify.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Opera Neon: il browser AI agentico di nuova generazione Opera Neon: il browser AI agentico di nuova gene...
Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi Wind Tre 'accende' il 5G Standalone in Italia: s...
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh OPPO Find X9 Pro: il camera phone con teleobiett...
DJI Romo, il robot aspirapolvere tutto trasparente DJI Romo, il robot aspirapolvere tutto trasparen...
DJI Osmo Nano: la piccola fotocamera alla prova sul campo DJI Osmo Nano: la piccola fotocamera alla prova ...
Attacco a OpenAI dal Giappone: Sora avre...
OpenAI annuncia un accordo strategico co...
Black Friday per e-bike Engwe: fino a 40...
Una PS5 grande come un tostapane: dove n...
Intel aveva pronta una scheda video di f...
Filippo Luna, CEO di Aira Italia: "...
Task Manager non si chiude e si moltipli...
Il CEO di OpenAI si lamenta della sua Te...
Shadow AI: il lato invisibile dell’innov...
Windows 7 ridotto a soli 69 MB: l'esperi...
Ancora problemi per i dischi SMR di West...
IA, zero trust, cifratura post quantum: ...
Accise diesel, la Legge di Bilancio 2026...
Chi possiede un'auto con motore PureTech...
Trump blocca le GPU NVIDIA Blackwell in ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 01:59.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v