Я пишу поисковик файловой системы, который принимает каталоги (обычно диски Windows) и фильтрует их как входные, а также ищет в каждом входном каталоге файлы, соответствующие входным фильтрам. Последовательно, я реализовал это так (упрощенная версия соответствующего кода):
foreach (var dir in Directories) {
Console.WriteLine("Searching: " + dir);
var s = new FSSearcher(dir, FileTypes, Keywords, SearchContents);
s.Search();
}
class FSSearcher {
[...]
private static List<string> Filetypes;
private static List<string> Keywords;
private static List<string> Results;
private static bool searchContents;
private static string SearchDirectory;
[...]
public FSSearcher(string d, List<string> f, List<string> k, bool s) {
SearchDirectory = d;
Filetypes = f;
Keywords = k;
Results = new List<string>();
searchContents = s;
}
public void Search() {
if (Directory.Exists(SearchDirectory)) {
Console.WriteLine("Searching dir: " + SearchDirectory);
[...]
}
}
}
Этот код работает правильно и как ожидалось. Никаких результатов не нужно собирать в конце цикла. FSSearcher - это «независимый класс». Теперь я хочу запустить этот цикл foreach
параллельно (разные физические диски, поэтому параллелизм не должен ограничиваться вводом / выводом), поэтому я изменил приведенный выше код на следующий (снова упрощенный код):
var ConcurrentDirectories = new ConcurrentBag<string>();
ConcurrentDirectories.Add("C:\\");
ConcurrentDirectories.Add("Z:\\");
var options = new ParallelOptions { MaxDegreeOfParallelism = ConcurrentDirectories.Count };
Parallel.ForEach(ConcurrentDirectories, options, (dir) => {
Console.WriteLine("Searching in parallel: " + dir);
var s = new FSSearcher(dir, FileTypes, Keywords, SearchContents);
s.Search();
});
Я предполагаю, что переменная s
является локальной для каждой итерации. Однако, это не так. Приведенный выше код дает следующий вывод:
Searching in parallel: Z:\
Searching in parallel: C:\
Searching dir: C:\
Searching dir: C:\ <=== this is expected to be Z:\
Похоже, что s
инициализируется для Z:\
в одной "итерации", а затем переназначается другому экземпляру FSSearcher для C:\
. Затем Search()
вызывается дважды для последнего назначенного объекта для C:\
.
Я прочитал все соответствующие сообщения SO для объяснения или решения, но не могу найти объяснение. Как это происходит и как я могу предотвратить это?
Заранее большое спасибо!