#c# #parallel.foreach
#c# #parallel.foreach
Вопрос:
Мне нужно выполнить поиск подстроки в более чем 10k файлах и вернуть первое совпадение. Для этого я написал этот метод, используя Parallel
класс:
public class FileSearchResult
{
public long Id { get; }
public string FilePath { get; }
public IList<SearchMatch> Matches { get; }
public FileSearchResult(long id, string filePath)
{
Id = id;
FilePath = filePath;
Matches = new List<SearchMatch>();
}
}
public class SearchMatch
{
public int Index { get; set; }
public int Length { get; set; }
}
public FileSearchResult[] SearchInFiles(string query, string[] filePathList)
{
if (string.IsNullOrWhiteSpace(query) || filePathList == null || filePathList.Length == 0)
{
return Array.Empty<FileSearchResult>();
}
Regex regex = new Regex(query, RegexOptions.IgnoreCase | RegexOptions.Multiline);
ConcurrentBag<FileSearchResult> matchesList = new ConcurrentBag<FileSearchResult>();
Parallel
.ForEach
(
filePathList,
(file, state, ix) =>
{
if (state.ShouldExitCurrentIteration)
{
return;
}
string fileContent = File.ReadAllText(file);
var results = regex.Matches(fileContent);
if (results.Count == 0)
{
return;
}
state.Break();
//if(state.LowestBreakIteration.HasValue)
//{
// Interlocked.Exchange(ref lowestBreakIteration, state.LowestBreakIteration.Value);
//}
FileSearchResult result = new FileSearchResult(ix, file);
for (int i = 0; i < results.Count; i)
{
if (state.ShouldExitCurrentIteration)
{
return;
}
var regexMatch = results[i];
SearchMatch match = new SearchMatch();
match.Index = regexMatch.Index;
match.Length = regexMatch.Length;
result.Matches.Add(match);
}
if (state.ShouldExitCurrentIteration)
{
return;
}
matchesList.Add(result);
}
);
return matchesList.ToArray();
}
public FileSearchResult[] SearchInFiles(string query, string sourceFolderPath)
{
if (string.IsNullOrWhiteSpace(sourceFolderPath) || !Directory.Exists(sourceFolderPath))
{
return Array.Empty<FileSearchResult>();
}
string[] filePathList = Directory.GetFiles(sourceFolderPath);
return SearchInFiles(query, filePathList);
}
В принципе, это работает, но если я ищу слово, которое есть во всех файлах, этот метод должен возвращать только 1-й найденный элемент, вместо этого я получаю 2 или иногда 3 элемента.
Если я отлаживаю вызов state.Break();
, я вижу, что иногда он вызывается более одного раза.
Что я делаю не так?
Комментарии:
1. Я бы сказал, что вы не делаете ничего неправильного, это ожидаемо. Посмотрите на learn.microsoft.com/en-us/previous-versions/dd460721 (v=против110) . Возможно, вместо этого используйте stop …
2. Я ожидал, что
ParallelLoopState.ShouldExitCurrentIteration
это будет true после любого.Break()
вызова, но я вижу, чтоyou cannot control whether other threads on a loop continue to run after either Stop or Break is called.