Я интересуюсь приобретением знаний о параллельном программировании в C#.NET (не как все, там должен знать, но основы и возможно некоторые хорошие методы), поэтому я решил повторно программировать старую мою программу, которую называют ImageSyncer. ImageSyncer является действительно простой программой, все, что он делает должен просканировать канавку папка и найти все файлы, заканчивающиеся .jpg, затем он вычисляет новое положение файлов на основе даты, они были взяты (парсинг xif-данных, или независимо от того, что это называют). После того, как местоположение генерировалось чеки программы для любых существующих файлов в том местоположении, и если Вы существуете, оно смотрит на прошлое время записи и файла для копирования, и файл "по-своему". Если это равно, файл пропускается. Если не md5 контрольная сумма обоих файлов создана и подобрана. Если там не идет ни в какое сравнение, файлу, который будет скопирован, дают новое местоположение, которое будет скопировано в (например, если он должен был быть скопирован в "C:\test.jpg", он копируется в "C:\test(1).jpg" вместо этого). Результат этой операции заполняется в очередь типа структуры, который содержит две строки, исходный файл и положение для копирования его в. Затем та очередь выполнена с помощью итераций, непока это не пусто, и файлы копируются.
Другими словами, существует 4 операции:
1. Scan directory for jpegs
2. Parse files for xif and generate copy-location
3. Check for file existence and if needed generate new path
4. Copy files
И таким образом, я хочу переписать эту программу, чтобы заставить его быть параллельным и смочь выполнить несколько из операций одновременно, и я задавался вопросом, чего лучшего способа достигнуть, который будет. Я имею, придумал две различных модели, о которых я могу думать, но никакой из них не мог бы хорошо работать вообще. Первый должен параллелизировать 4 шага старой программы, так, чтобы, когда шаг нужно быть выполнен, он был сделан на нескольких потоках, и когда всем из шага 1 является законченный шаг 2, начался. Другой один (который я нахожу более интересными, потому что я понятия не имею о том, как сделать это) должен создать своего рода модель рабочего и потребителя, поэтому когда поток закончен с шагом 1, другой вступает во владение и выполняет шаг 2 в том объекте (или что-то как этот). Но, как сказано, я не знаю, является ли какой-либо из них какими-либо хорошими решениями. Кроме того, я не знаю много о параллельном программировании вообще. Я знаю, как сделать поток, и как заставить его выполнить взятие функции в объекте как его единственный параметр, и я также использовал BackgroundWorker-класс в одном случае, но я не настолько знаком ни с одним из них.
Любой вход ценился бы.
Есть несколько вариантов:
Parallel LINQ : Выполнение запросов на многоядерных процессорах
Библиотека параллельных задач (TPL): Оптимизация управляемого кода для многоядерных машин
Если вас интересуют основные примитивы и концепции потоковой передачи: Потоковая обработка в C #
[Но, как отметил @John Knoeller, приведенный вами пример, скорее всего, связан с последовательным вводом-выводом]
Это ссылка, которую я использую для потока C #: http://www.albahari.com/threading/
В виде одного PDF-файла : http://www.albahari.com/threading/threading.pdf
Для вашего второго подхода:
Я работал над некоторыми многопоточными приложениями производителя / потребителя, где каждая задача представляет собой некоторый код, который повторяется вечно. Внешний «инициализатор» запускает отдельный поток для каждой задачи и инициализирует EventWaitHandle для каждой задачи. Для каждой задачи есть глобальная очередь, которую можно использовать для производства / потребления ввода.
В вашем случае ваша внешняя программа добавит каждый каталог в очередь для Task1 и установит EventWaitHandler для Task1. Задача 1 «проснется» от своего EventWaitHandler, получит количество каталогов в своей очереди, а затем, пока счетчик больше 0, получит каталог из очереди, просканирует все файлы .jpgs и добавит каждое местоположение .jpg. во вторую очередь и установите EventWaitHandle для задачи 2. Задача 2 считывает входные данные, обрабатывает их, пересылает их в очередь для Задачи 3 ...
Может быть немного сложно заставить все блокировки работать правильно (я в основном блокирую любой доступ к очереди, даже такой простой, как получение ее счетчика). .NET 4.0 должен иметь структуры данных, которые будут автоматически поддерживать очередь производителя / потребителя без блокировок.
Интересная проблема. Я придумал два подхода. Первый основан на PLinq, а второй - на te Rx Framework.
Первый параллельно итерирует файлы. Второй асинхронно генерирует файлы из каталога.
Вот как это выглядит в упрощенном варианте (Первый метод требует .Net 4.0, поскольку использует PLinq)
string direcory = "Mydirectory";
var jpegFiles = System.IO.Directory.EnumerateFiles(direcory,"*.jpg");
// -- PLinq --------------------------------------------
jpegFiles
.AsParallel()
.Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) })
.Do(fileInfo =>
{
if (!File.Exists(fileInfo.NewLocation ) ||
(File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation)))
File.Copy(fileInfo.OldLocation,fileInfo.NewLocation);
})
.Run();
// -----------------------------------------------------
//-- Rx Framework ---------------------------------------------
var resetEvent = new AutoResetEvent(false);
var doTheWork =
jpegFiles.ToObservable()
.Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) })
.Subscribe( fileInfo =>
{
if (!File.Exists(fileInfo.NewLocation ) ||
(File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation)))
File.Copy(fileInfo.OldLocation,fileInfo.NewLocation);
},() => resetEvent.Set());
resetEvent.WaitOne();
doTheWork.Dispose();
// -----------------------------------------------------