Язык программирования C#9 и платформа .NET5
Часть 290 из 642 Информация о книге
В этом примере требуется дополнительный пакет NuGet (
). Чтобы добавить его в проект, введите следующую команду (целиком в одной строке) в окне командной строки (в каталоге, где находится файл решения) или в консоли диспетчера пакетов в Visual Studio:System.Drawing.Commondotnet add DataParallelismWithForEach package System.Drawing.CommonДважды щелкнув на имени файла
(может потребоваться развернуть узелMainWindow.xaml.cs), добавьте в его начало представленные ниже операторыMainWindow.xaml:using// Обеспечить доступ к перечисленным ниже пространствам имен!// (System.Threading.Tasks уже должно присутствовать благодаря// выбранному шаблону.)using System;using System.Drawing;using System.Threading.Tasks;using System.Threading;using System.Windows;using System.IO;На заметку! Вы должны обновить строку, передаваемую методу
, чтобы в ней был указан конкретный путь к каталогу на вашей машине, который содержит файлы изображений. Для вашего удобства в каталогDirectory.GetFiles()включено несколько примеров изображений (поставляемых в составе операционной системы Windows).TestPicturespublic partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void cmdCancel_Click(object sender, EventArgs e){// Код метода будет вскоре обновлен.}private void cmdProcess_Click(object sender, EventArgs e){ProcessFiles();this.Title = "Processing Complete";}private void ProcessFiles(){// Загрузить все файлы *.jpg и создать новый каталог// для модифицированных данных.// Получить путь к каталогу с исполняемым файлом.// В режиме отладки VS 2019 текущим каталогом будет// <каталог npoeктa>\bin\debug\net5.0 - windows.// В случае VS Code или команды dotnet run текущим// каталогом будет <каталог проекта>.var basePath = Directory.GetCurrentDirectory();var pictureDirectory =Path.Combine(basePath, "TestPictures");var outputDirectory =Path.Combine(basePath, "ModifiedPictures");// Удались любые существующие файлы.if (Directory.Exists(outputDirectory)){Directory.Delete(outputDirectory, true);}Directory.CreateDirectory(outputDirectory);string[] files = Directory.GetFiles(pictureDirectory,"*.jpg", SearchOption.AllDirectories);// Обработать данные изображений в блокирующей манере.foreach (string currentFile in files){string filename =System.IO.Path.GetFileName(currentFile);// Вывести идентификатор потока, обрабатывающего текущее изображение.this.Title = $"Processing {filename}on thread {Thread.CurrentThread.ManagedThreadId}";using (Bitmap bitmap = new Bitmap(currentFile)){bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);bitmap.Save(System.IO.Path.Combine(outputDirectory, filename));}}}}На заметку! В случае получения сообщения об ошибке, связанной с неоднозначностью имени
междуPathиSystem.IO.Path, либо удалите операторSystem.Windows.Shapes.Pathдляusing, либо добавьтеSystem.Windows.ShapesкSystem.IO:PathSystem.IO.Path.Combine(...).Обратите внимание, что метод
выполнит поворот изображения в каждом файлеProcessFiles()из указанного каталога. В настоящее время вся работа происходит в первичном потоке исполняемой программы. Следовательно, после щелчка на кнопке Click to Flip Your Images! (Щелкните для поворота ваших изображений) программа выглядит зависшей. Вдобавок заголовок окна также сообщит о том, что файл обрабатывается тем же самым первичным потоком, т.к. в наличии есть только один поток выполнения.*.jpgЧтобы обрабатывать файлы на как можно большем количестве процессоров, текущий цикл
можно заменить вызовом методаforeach. Вспомните, что этот метод имеет множество перегруженных версий. Простейшая форма метода принимает совместимый сParallel.ForEach()объект, который содержит элементы, подлежащие обработке (например, строковый массивIEnumerable<T>), и делегатfiles, указывающий на метод, который будет выполнять необходимую работу.Action<T>