использование ThreadPools для поиска по спискам объектов - PullRequest
0 голосов
/ 18 декабря 2008

У меня есть эти объекты-контейнеры (давайте назовем их контейнерами) в списке. Каждый из этих объектов-контейнеров, в свою очередь, имеет 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

1 Ответ

2 голосов
/ 18 декабря 2008

По фрагменту, который вы публикуете, трудно увидеть, но, судя по симптомам, я бы посмотрел на AllWordsMatcher (ищите статическое состояние). Если AllWordsMatcher имеет состояние, вы должны также проверить, что вы создаете новый экземпляр для каждого потока.

В более общем плане я бы посмотрел на все экземпляры, вовлеченные в процесс сопоставления / поиска, особенно на рабочие объекты, используемые при многопоточности. Из прошлого опыта, проблема обычно лежит там. (В этом случае легко взглянуть на граф объектов, представляющий контейнер бизнес-данных / DataItem)

...