Multi-thread restituisce un singolo risultato SQL

2

Sto avendo qualche difficoltà con MySQL e la restituzione di una riga univoca in un thread. Lo voglio in modo che il thread cercherà una riga dalla tabella in cui il bit (vedi sotto) è falso e viene restituita solo una riga. Ma non voglio che gli altri thread restituiscano lo stesso risultato se ci fosse qualche condizione di competizione in cui lo stesso risultato viene restituito al thread; perché il thread eseguirà molta elaborazione dalla parte posteriore di questo risultato e non voglio la duplicazione.

Sfondo: Ho un database MySQL che contiene 3 colonne (id, text, bit). L'ID viene incrementato automaticamente. Ho un'applicazione Ruby multi-thread che legge, aggiorna e inserisce righe nella tabella.

Lo pseudo codice per il thread è il seguente:

select a row from the table where the bit is false
do some processing with the text returned from that row
insert more rows with bit set to false

Ho provato un semplice test con uno script multi-thread che utilizza quanto segue:

SELECT id, text FROM table WHERE bit =FALSE LIMIT 1 FOR UPDATE

Ma ogni thread restituisce la stessa riga. Ho disabilitato l'autocommit secondo la raccomandazione. Poiché sto omettendo qualsiasi commit, mi aspetto che gli altri thread abbiano un risultato diverso poiché la riga è bloccata.

Mi manca qualcosa o dovrei guardare usando un altro metodo?

    
posta Matt S 27.08.2013 - 19:47
fonte

2 risposte

1

Puoi aggiungere un'altra colonna che tiene traccia indipendentemente dal fatto che una determinata riga sia "ritirata" dall'applicazione. Questo potrebbe essere un buon posto per un proc memorizzato. Gli altri thread selezionerebbero quindi la prima riga dove "bit" è falso e "checked_out" è falso.

Un'altra opzione è quella di dedicare un singolo thread per estrarre gli id e distribuirli ai thread worker.

Sembra che tu stia implementando una coda, nel qual caso potresti anche voler ricercare i vari sistemi di coda / di messaggistica.

Ulteriori opzioni ...

Se sai che avrai sempre un numero fisso di thread, puoi aggiungere una condizione mod alla tua query. ad es. "dove (bit = falso) e (id% 4 = 0)". Ciò comporta il rischio di oggetti mancanti se uno dei fili si arresta o cade dietro.

Ancora un'altra cosa da considerare è forse considerare di fare solo il tuo lavoro in un singolo thread. Il tuo server MySQL gestirà solo così tanto, quindi dovresti profilare il tuo profilo per vedere se stai effettivamente ottenendo più risultati con più thread. Quindi se i thread stanno facendo solo db read & scrive, potrebbe non esserci un vantaggio. D'altra parte, se quello che stai facendo è un uso intensivo del processore, qualcosa di simile all'elaborazione delle immagini, i thread saranno probabilmente di aiuto.

    
risposta data 27.08.2013 - 21:22
fonte
0

Ecco un approccio che potrebbe aiutarti a ... separare le tue preoccupazioni ...

Dovresti avere una classe Supervisor separata che controlli le letture dei dati. Il database è per l'archiviazione dei dati, troverai più semplice lasciare che l'applicazione si preoccupi di ogni altra cosa.

La classe Supervisor è un singleton ed è responsabile della gestione di quali record hanno e non sono stati elaborati e di emettere record non elaborati sui thread worker. Il Supervisore ha i seguenti metodi a cui è possibile accedere solo da un thread alla volta:

  1. Ottieni registro non elaborato
  2. Crea record

GetUnproccessedRecord legge l'elemento successivo da un oggetto coda interno e lo restituisce al chiamante. Quando la coda è vuota, interrogare il database per i record inseriti dopo l'ultima query, quindi aggiorna la sua ultima variabile temporale di query.

Quando un thread ha terminato l'elaborazione di un record, chiama il metodo CreateRecord del supervisore. Il supervisore può quindi inserirlo immediatamente nel DB o inserirlo in un elenco per inserimenti batch per prestazioni migliori. Il supervisore posizionerà il record anche nella sua coda di registrazione non elaborata. Il thread worker ora chiama GetUnproccessedRecord record e il ciclo si ripete.

Non caricare il database, lascia che il codice dell'applicazione esegua il sollevamento e la sincronizzazione; la tua applicazione è stata creata da te, quindi sa come gestire la sincronizzazione dei record.

    
risposta data 30.08.2017 - 17:49
fonte

Leggi altre domande sui tag