2011-06-19 6 views
4

Je reçois des tonnes de données statistiques que j'ai besoin d'insérer dans le db. Je voudrais mettre en place une sorte de file d'attente ou de classe FIFO qui conserve toutes les données et quand il atteint un nombre spécifique (tampon), il enverra ces données au SQL via l'insertion en bloc. Cela devrait être thread-safe.FIFO/QUEUE avec buffer et thread-safe

Je sais comment faire l'insert en vrac. Des conseils pour faire la queue/liste?

Merci

+0

Pourquoi doit-il être FIFO? – adrianm

+0

Courez-vous sous .Net 4? – svick

Répondre

1

La bibliothèque de classes de base .net a ConcurrentQueue(Of T). Il suffit d'importer System.Collections.Concurrent.

Modifier: Si vous devez utiliser une file d'attente, vous pouvez créer une classe/module wrapper qui déclenche un événement lorsque le compteur (buffer) atteint une certaine quantité.

+0

Et puis la sécurité de thread .... –

+0

Qu'en est-il d'une fonction de rappel lorsque vous atteignez la limite de la mémoire tampon et que vous avez comme threadsafe? – Shay

+0

@Henk - Ahhh. Je pensais que c'était trop simple ... – aligray

0

Si vous n'avez pas besoin de FIFO stricte, je pense que vous devriez utiliser BlockingCollection.

Il est thread-safe et la mise en œuvre regarderait somthing comme:

var collection = new BlockingCollection<Data>(); 

var sqlinserter = Task.Factory.StartNew(UpdateSql()); 

while (true) { 
    Data statistics = FetchStatistics(); 
    if (statistics == null) 
     break; 
    collection.Add(statistics); 
} 
collection.CompleteAdding(); 
sqlinserter.Wait(); 

Modifier vu que vous vouliez insérer un nombre spécifique d'éléments dans chaque lot

void UpdateSql() { 
    var batch = new List<Data>(); 
    foreach (var item in collection.GetConsumingEnumerable()) { 
     batch.Add(item); 
     if (batch.Count > SomeBatchSize) { 
      InsertIntoSql(batch); 
      batch.Clear(); 
     } 
    } 
    if (batch.Count > 0) 
     InsertIntoSql(batch); // insert remaining items 
} 
-1

C'est un moyen sûr de faire avec. Principalement, vous voulez éviter toute situation où vous pouvez être "coincé" dans une synclock.

Public Class TSQueue(Of T) 

    Private q As New Queue(Of T) 
    Public Property threshold As Integer = 100 
    Public Event ThresholdHit As EventHandler(Of EventArgs) 

    Public Sub EnqueueSafe(value As T) 
     Dim notify As Boolean = False 
     SyncLock q 
      q.Enqueue(value) 
      If q.Count >= threshold Then 
       notify = True 
      End If 
     End SyncLock 
     If notify Then 
      RaiseEvent ThresholdHit(Me, EventArgs.Empty) 
     End If 
    End Sub 

    Public Function DequeueSafe() As T 
     SyncLock q 
      Return q.Dequeue() 
     End SyncLock 
    End Function 

    Public Function DequeueAllSafe() As T() 
     Dim out() As T 
     SyncLock q 
      out = q.ToArray() 
      q.Clear() 
     End SyncLock 
     Return out 
    End Function 

    Public Function CountSafe() As Integer 
     SyncLock q 
      Return q.Count 
     End SyncLock 
    End Function 

End Class 
+0

Je suis surpris que ce ne soit pas la réponse car la question était effectivement "... mettre en place une sorte de file d'attente ou de classe FIFO qui garde toutes les données et quand elle atteint un nombre spécifique (buffer), il enverra ces données au SQL via une insertion en masse, ce qui devrait être sûr pour les threads, des conseils pour faire la file d'attente/liste? l'événement ThresholdHit déclenchera la sauvegarde des données et la file d'attente d'arrière-plan sera threadsafe via les instructions synclock. – DarrenMB