Многопоточность в Aspose.Slides для .NET
Введение
Хотя параллельная работа с презентациями возможна (за исключением парсинга/загрузки/клонирования) и обычно всё проходит гладко (в большинстве случаев), существует небольшая вероятность получения неправильных результатов при использовании библиотеки в нескольких потоках.
Мы настоятельно рекомендуем не использовать один экземпляр Presentation в многопоточной среде, поскольку это может привести к непредсказуемым ошибкам или сбоям, которые трудно обнаружить.
Загрузка, сохранение и/или клонирование экземпляра класса Presentation в нескольких потоках не безопасны. Такие операции не поддерживаются. Если необходимо выполнять такие задачи, следует параллелить операции, используя несколько одно‑поточных процессов — каждый из этих процессов должен использовать свой собственный экземпляр презентации.
Параллельное преобразование слайдов презентации в изображения
Допустим, мы хотим параллельно преобразовать все слайды PowerPoint‑презентации в изображения PNG. Поскольку использование одного экземпляра Presentation в нескольких потоках небезопасно, мы делим слайды презентации на отдельные презентации и конвертируем слайды в изображения параллельно, используя каждую презентацию в отдельном потоке. Ниже приведён пример кода, показывающий, как это сделать.
var inputFilePath = "sample.pptx";
var outputFilePathTemplate = "slide_{0}.png";
var imageScale = 2;
using var presentation = new Presentation(inputFilePath);
var slideCount = presentation.Slides.Count;
var slideSize = presentation.SlideSize.Size;
var conversionTasks = new List<Task>(slideCount);
for (var slideIndex = 0; slideIndex < slideCount; slideIndex++)
{
// Извлечь слайд i в отдельную презентацию.
var slidePresentation = new Presentation();
slidePresentation.SlideSize.SetSize(slideSize.Width, slideSize.Height, SlideSizeScaleType.DoNotScale);
slidePresentation.Slides.RemoveAt(0);
slidePresentation.Slides.AddClone(presentation.Slides[slideIndex]);
// Преобразовать слайд в изображение в отдельной задаче.
var slideNumber = slideIndex + 1;
conversionTasks.Add(Task.Run(() =>
{
try
{
var slide = slidePresentation.Slides[0];
using var image = slide.GetImage(imageScale, imageScale);
var imageFilePath = string.Format(outputFilePathTemplate, slideNumber);
image.Save(imageFilePath, ImageFormat.Png);
}
finally
{
slidePresentation.Dispose();
}
}));
}
await Task.WhenAll(conversionTasks);
FAQ
Нужно ли вызывать настройку лицензии в каждом потоке?
Нет. Достаточно выполнить её один раз за процесс/домен приложения до запуска потоков. Если license setup может вызываться одновременно (например, при отложенной инициализации), синхронизируйте этот вызов, поскольку сам метод настройки лицензии не является потокобезопасным.
Могу ли я передавать объекты Presentation или Slide между потоками?
Передача «живых» объектов презентации между потоками не рекомендуется: используйте независимые экземпляры для каждого потока или предварительно создайте отдельные презентации/контейнеры слайдов для каждого потока. Такой подход соответствует общей рекомендации не делиться одним экземпляром презентации между потоками.
Безопасно ли параллельно экспортировать в разные форматы (PDF, HTML, изображения), если каждый поток имеет свой собственный экземпляр Presentation?
Да. При наличии независимых экземпляров и отдельных путей вывода такие задачи обычно корректно параллелятся; избегайте совместного использования объектов презентации и общих потоков ввода/вывода.
Что делать с глобальными настройками шрифтов (папки, замены) в многопоточной среде?
Инициализируйте все глобальные настройки шрифтов до запуска потоков и не меняйте их во время параллельной работы. Это устраняет гонки при доступе к общим ресурсам шрифтов.