Цикл Parallel.For для проверки орфографии с использованием NHunspell и C#

У меня есть список строк, и если я запускаю проверку орфографии с использованием NHunspell последовательно, то все работает нормально; но если я использую цикл Parallel.For для List, приложение перестает работать в середине (некоторая ошибка нарушения адреса)

public static bool IsSpellingRight(string inputword, byte[] frDic, byte[] frAff, byte[] enDic, byte[] enAff)
{
    if (inputword.Length != 0)
    {
        bool correct;
        if (IsEnglish(inputword))
        {
            using (var hunspell = new Hunspell(enAff, enDic))
            {
                correct = hunspell.Spell(inputword);
            }
        }
        else
        {
            using (var hunspell = new Hunspell(frAff, frDic))
            {
                correct = hunspell.Spell(inputword);
            }
        }
        return correct ;
    }

    return false;
}

Редактировать:

var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;

var poptions = new ParallelOptions();

// Keep one core/CPU free...
poptions.MaxDegreeOfParallelism = Environment.ProcessorCount - 1;
Task task = Task.Factory.StartNew(delegate
{
    Parallel.For(0, total, poptions, i =>
    {
        if (words[i] != "")
        {
            _totalWords++;

            if (IsSpellingRight(words[i],dictFileBytes,
                affFileBytes,dictFileBytesE,affFileBytesE))
            {
                // do something   

            }
            else
            {
                BeginInvoke((Action) (() =>
                {
                    //do something on UI thread
                }));
            }
        }
    });
}, tokenSource.Token);

task.ContinueWith((t) => BeginInvoke((Action) (() =>
{
    MessaageBox.Show("Done");
})));

2 ответа

Решение

Я думаю, вы должны забыть о том, что ваш параллельный цикл реализует все правильно

Вам известно о том, что этот код загружает и создает словарь:

    using (var hunspell = new Hunspell(enAff, enDic))
    {
        correct = hunspell.Spell(inputword);
    }

Вы загружаете и строите словарь снова и снова с вашим кодом. Это ужасно медленно! Загрузите словарь один раз и проверьте все слова, а затем утилизируйте его. И не делайте этого параллельно, потому что объекты Hunspell не являются потокобезопасными.

Pseodocode:

Hunspell hunspell = null;
try
{
    hunspell = new Hunspell(enAff, enDic)

    for( ... )
    {
      hunspell.Spell(inputword[i]);
    }
    }
}
finally
{
    if( hunspell != null ) hunspell.Dispose();
}

Если вам нужно проверить массивные слова параллельно, рассмотрите эту статью: http://www.codeproject.com/Articles/43769/Spell-Check-Hyphenation-and-Thesaurus-for-NET-with

Хорошо, теперь я вижу потенциальную проблему. В соответствии

_totalWords++;

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

редактировать: также вы можете использовать Interlocked.Increment(ref val);, что было бы быстрее, чем простая блокировка.

edit2: Вот как должна выглядеть блокировка, описанная в комментарии, для проблемы, с которой вы столкнулись:

static object Locker = new object();    //anywhere in the class

//then in your method
if (inputword.Length != 0)
{
   bool correct;
   bool isEnglish;
   lock(Locker) {isEnglish = IsEnglish(inputword);}
   if(isEnglish)
   {
       //..do your stuff
   }
    //rest of your function
}
Другие вопросы по тегам