У меня есть эти объекты-контейнеры (давайте назовем их контейнерами) в списке. Каждый из этих объектов-контейнеров, в свою очередь, имеет DataItem
(или производное) в списке. В типичном сценарии у пользователя будет 15-20 объектов-контейнеров с 1000-5000 DataItems
каждый. Тогда есть несколько DataMatcher
объектов, которые можно использовать для различных типов поиска. Они работают в основном нормально (так как у меня есть несколько сотен модульных тестов), но для того, чтобы мое приложение WPF стало быстрым и отзывчивым, я решил использовать ThreadPool
для этой задачи. Таким образом, у меня есть DataItemCommandRunner , который выполняется на объекте-контейнере и в основном выполняет каждый делегат в списке, который он принимает в качестве параметра для каждого DataItem
по очереди; Я использую ThreadPool
, чтобы поставить в очередь один поток для каждого Контейнера, чтобы теоретически поиск был максимально эффективным на многоядерных компьютерах и т. Д.
Это в основном делается в DataItemUpdater классе, который выглядит примерно так:
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);
}
}
(Бесполезный параметр объекта для RunCommandsOnContainer вызван тем, что я экспериментирую с этим и без использования потоков, и для одного из них требуется какой-либо параметр. Кроме того, для приоритета установлено значение AboveNormal это просто эксперимент.)
Это прекрасно работает для всех, кроме одного сценария - когда я использую объектный тип AllWordsMatcher
, который будет искать DataItem
объекты, содержащие все слова, которые ищутся (в отличие от любых слов, точной фразы или регулярного выражения, например) .
Это довольно простой somestring.Contains(eachWord)
объект, основанный на модульных тестах. Но здесь кроется какая-то волосатая странность.
Когда RunCommandsOnContainer работает с использованием потоков ThreadPool
, он возвращает безумные результаты. Скажем, у меня есть такая строка:
var someString = "123123123 - just some numbers";
И я запускаю это:
var res = someString.Contains("data");
Когда он запускается, он на самом деле возвращает true довольно много - у меня есть отладочная информация, которая показывает, что он возвращает true для пустых строк и других строк, которые просто не содержат данных. Кроме того, он иногда возвращает false, даже если строка действительно содержит искомые данные.
Кикер во всем этом? Почему я подозреваю ThreadPool
, а не мой собственный код?
Когда я запускаю команду RunCommandsOnContainer () для каждого контейнера в моем основном потоке (т. Е. Блокировки пользовательского интерфейса и всего остального), она работает на 100% правильно - каждый раз! Он никогда не находит ничего, чего не должен, и никогда не пропускает ничего, что должен был найти.
Однако, как только я использую ThreadPool
, он начинает находить партию предметов , которую он не должен, в то время как иногда не находит предметы, которые он должен.
Я понимаю, что это сложная проблема (пытаться отладить, это точно!), Но любое понимание того, почему и как это исправить, было бы очень полезно!
Спасибо!
Rune