2008-12-18 3 views
0

J'ai ces objets conteneur (appelons-les Container) dans une liste. Chacun de ces objets Container a un DataItem (ou un dérivé) dans une liste. Dans un scénario typique, un utilisateur aura 15-20 objets Container avec 1000-5000 DataItems chacun. Ensuite, il y a quelques objets DataMatcher qui peuvent être utilisés pour différents types de recherches. Ceux-ci fonctionnent principalement bien (puisque j'ai plusieurs centaines de tests unitaires sur eux), mais afin de rendre mon application WPF se sentir rapide et réactif, j'ai décidé que je devrais utiliser le ThreadPool pour cette tâche. Ainsi j'ai un DataItemCommandRunner qui s'exécute sur un objet Container, et effectue fondamentalement chaque délégué dans une liste qu'il prend en paramètre sur chaque DataItem à tour de rôle; J'utilise le ThreadPool à faire la queue un fil pour chaque conteneur, de sorte que la recherche en théorie devrait être aussi efficace que possible sur les ordinateurs multi-core etc.Utilisation de ThreadPools pour effectuer une recherche dans les listes d'objets

Ceci est essentiellement fait dans une classe DataItemUpdater qui ressemble à ceci:.

public class DataItemUpdater 
{ 
    private Container ch; 
    private IEnumerable<DataItemCommand> cmds; 

    public DataItemUpdater(Container container, IEnumerable<DataItemCommand> commandList) 
    { 
     ch = container; 
     cmds = commandList; 
    } 

    public void RunCommandsOnContainer(object useless) 
    { 
     Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; 
     foreach (DataItem di in ch.ItemList) 
     { 
      foreach (var cmd in cmds) 
      { 
       cmd(sh); 
      } 
     } 
     //Console.WriteLine("Done running for {0}", ch.DisplayName); 
    } 
} 

(le paramètre objet inutile pour RunCommandsOnContainer est parce que je suis expérimenté avec cela avec et sans l'aide de fils, et l'un d'entre eux nécessite un paramètre aussi, le réglage de la priorité à abovenormal est juste une expérience a s bien.)

Cela fonctionne très bien pour tous sauf un scénario - lorsque j'utilise le type d'objet AllWordsMatcher qui recherchera DataItem objets contenant tous les mots recherchés (par opposition à tous les mots, expression exacte ou expression régulière par exemple).

Il s'agit d'un objet simple basé sur somestring.Contains(eachWord), soutenu par des tests unitaires. Mais ici réside une étrangeté poilue.

Lorsque le RunCommandsOnContainer s'exécute à l'aide des threads ThreadPool, les résultats sont incorrects. Dire que j'ai une chaîne comme ceci:

var someString = "123123123 - just some numbers"; 

Et je lance ceci:

var res = someString.Contains("data"); 

Quand il court, cela va revenir en fait vrai pas mal - j'ai des informations de débogage qui montre le renvoyer vrai pour chaînes vides et autres chaînes qui ne contiennent tout simplement pas les données. En outre, il retournera parfois false même si la chaîne contient réellement les données recherchées.

Le kicker dans tout ça? Pourquoi est-ce que je suspecte le ThreadPool et pas mon propre code? Lorsque j'exécute la commande RunCommandsOnContainer() pour chaque conteneur de mon thread principal (c'est-à-dire le verrouillage de l'interface utilisateur et tout le reste), cela fonctionne correctement à 100% - à chaque fois! Il ne trouve jamais rien qu'il ne devrait pas, et il ne saute jamais tout ce qu'il aurait dû trouver.

Cependant, dès que j'utilise le ThreadPool, il commence à trouver un beaucoup d'éléments il ne devrait pas, alors que parfois ne trouve pas les éléments qu'il le devrait.

Je réalise qu'il s'agit d'un problème complexe (il est douloureux d'essayer de déboguer, c'est sûr!), Mais toute idée de pourquoi et comment résoudre ce problème serait grandement appréciée!

Merci!

Rune

Répondre

2

Il est un peu difficile de voir du fragment que vous affichez, mais à en juger par les symptômes, je regarde le AllWordsMatcher (cherchez état statique). Si AllWordsMatcher est à état, vous devez également vérifier que vous créez une nouvelle instance pour chaque thread. Plus généralement, je regarderais toutes les instances impliquées dans le processus de recherche/correspondance, en particulier sur les objets de travail utilisés en multithread. De l'expérience passée, le problème réside habituellement là. (Il est facile de regarder trop le graphe d'objets représentant vos données d'entreprise Container/DataItem dans ce cas)

+0

Vous êtes assez proche pour le trouver - ce n'était pas un état statique en soi, mais une variable de niveau classe qui a été partagé entre les instances. Erreur stupide, stupide, maintenant fixée. Merci beaucoup! –

Questions connexes