2010-09-28 9 views
1

Je voulais implémenter un service Windows qui capture les fichiers délimités à plat dans un dossier pour l'importer dans la base de données. Ce que je prévois à l'origine est d'avoir un FileSystemWatcher regardant de nouveaux fichiers importés et créant un nouveau thread pour l'importation.La bonne technique de file d'attente de file d'attente dans C#?

Je voulais savoir comment je devrais implémenter correctement un algorithme pour cela et quelle technique devrais-je utiliser? Est-ce que je vais dans la bonne direction?

+0

Pourquoi le service et le dossier spécial de dépôt? Pourquoi ne pas simplement faire glisser un groupe de fichiers sur un fichier .exe normal et l'exécuter, faire l'importation dans la base de données, puis mourir? – Reinderien

+0

@Reinderien: J'imagine que le terme "abandonné" ici ne se réfère pas au processus d'un utilisateur faisant glisser et déposer des fichiers, mais plutôt à un système produisant des fichiers dans un certain dossier. –

+0

@Fredrik, vous avez raison. J'ai mentionné qu'il est déposé dans un dossier. –

Répondre

0

La création d'un fil par message sera probablement trop chère. Si vous pouvez utiliser .NET 4, vous pouvez démarrer un Task pour chaque message. Cela exécuterait le code sur un thread de pool de threads et réduirait ainsi la surcharge liée à la création de threads.

Vous pouvez également faire quelque chose de similaire avec asynchronous delegates si .NET 4 n'est pas une option. Cependant, le code devient un peu plus compliqué dans ce cas. Cela utiliserait également le pool de threads et vous éviterait de devoir créer un nouveau thread pour chaque message.

+0

merci pour la suggestion, cependant, nous sommes toujours bloqués en utilisant 3.5 sp1. –

+0

@Martin: C'est bon. Vous pouvez télécharger le framework Reactive Extensions. C'est fondamentalement un backport du TPL. –

1

J'ai développé un produit comme celui-ci pour un client. Le service surveillait un certain nombre de dossiers pour de nouveaux fichiers et lorsque les fichiers ont été découverts, les fichiers ont été lus, traités (imprimés sur des imprimantes de codes à barres), archivés et supprimés. Nous avons utilisé un "découvreur" couche qui a découvert des fichiers utilisant FileSystemWatcher ou interrogation en fonction de l'environnement (puisque FileSystemWatcher n'est pas fiable lors de la surveillance par exemple des partages samba), une couche "lecteur de fichiers" et une couche "processeur". La couche "discoverer" a découvert des fichiers et a placé les noms de fichiers dans une liste que la couche "file reader" a traitée. La couche "découvreur" signalait qu'il y avait de nouveaux fichiers à traiter en paramétrant un événement que la couche "lecteur de fichiers" attendait. La couche "lecteur de fichiers" lit ensuite les fichiers (en utilisant la fonctionnalité Réessayer car vous pouvez recevoir des notifications pour les nouveaux fichiers avant que les fichiers aient été complètement écrits par le processus qui crée le fichier). Une fois que le calque "lecteur de fichiers" a lu le fichier, un nouveau thread "processeur" a été créé en utilisant ThreadPool.QueueWorkItem pour traiter le contenu du fichier.

Lorsque le fichier a été traité, le fichier d'origine a été copié dans une archive et supprimé de l'emplacement d'origine. Les archives ont également été nettoyées régulièrement pour éviter d'inonder le serveur. Les archives étaient parfaites pour le dépannage.

Depuis plus de deux ans, il est utilisé dans la production dans différents environnements et s'est révélé très fiable.

+0

merci pour cette confirmation, laissez-moi simplement attendre d'autres entrées aussi bien. votre commentaire est bien apprécié. –

1

J'ai fourni un service qui le fait aussi. J'interroge via un temporisateur dont le gestionnaire d'événements écoulé agit en tant que superviseur, en ajoutant de nouveaux fichiers à une file d'attente et en lançant un nombre configurable de threads qui consomment la file d'attente. Une fois les fichiers traités, le minuteur redémarre.

Chaque thread incluant le gestionnaire d'événements intercepte et signale toutes les exceptions. Le service est toujours en cours d'exécution et j'utilise une application d'interface utilisateur distincte pour indiquer au service de démarrer et d'arrêter la minuterie. Cette approche a été solide comme le roc et le service n'a jamais chuté dans plusieurs années de traitement.

1

L'approche traditionnelle consiste à créer un ensemble fini de threads (peut être aussi petit que 1) et de les faire regarder une file d'attente de blocage. Le code dans les gestionnaires d'événements mettra en file d'attente les éléments de travail pendant que le (s) thread (s) de travail les supprime et les traite.Il peut ressembler à ce qui suit qui utilise la classe BlockingCollection qui est disponible dans .NET 4.0 ou dans le cadre du téléchargement Reactive Extensions.

Remarque: Le code est court et concis pour des raisons de concision. Vous devrez développer et durcir vous-même.

public class Example 
{ 
    private BlockingCollection<string> m_Queue = new BlockingCollection<string>(); 

    public Example() 
    { 
    var thread = new Thread(Process); 
    thread.IsBackground = true; 
    thread.Start(); 
    } 

    private void FileSystemWatcher_Event(object sender, EventArgs args) 
    { 
    string file = GetFilePathFromEventArgs(args); 
    m_Queue.Add(file); 
    } 

    private void Process() 
    { 
    while (true) 
    { 
     string file = m_Queue.Take(); 
     // Process the file here. 
    } 
    } 
} 

Vous pouvez profiter de la classe Task dans le TPL pour une plus moderne et ThreadPool approche -comme. Vous devez démarrer une nouvelle tâche pour chaque fichier (ou peut-être les traiter par lots) qui doit être traitée. La seule chose que je vois avec cette approche est qu'il serait plus difficile de contrôler le nombre de connexions à la base de données ouvertes simultanément. Ce n'est certainement pas un showstopper et il pourrait être sans importance.

Le FileSystemWatcher a été connu pour être un peu squameuse il est souvent conseillé d'utiliser une méthode secondaire de découvrir les changements de fichiers au cas où ils seront oubliées par le FileSystemWatcher. Votre kilométrage peut varier sur ce problème.