Цикл 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
}