Multithreading in Aspose.Slides for Python

Introduction

While parallel work with presentations is possible (besides parsing/loading/cloning) and everything goes well (most times), there is a small chance you might get incorrect results when you use the library in multiple threads.

We strongly recommend that you do not use a single Presentation instance in a multi-threading environment because it might result in unpredictable errors or failures that are not easily detected.

It is not safe to load, save, and/or clone an instance of a Presentation class in multiple threads. Such operations are not supported. If you need to perform such tasks, you have to parallel the operations using several single-threaded processes—and each of these processes should use its own presentation instance.

Convert Presentation Slides to Images in Parallel

Let’s say we want to convert all the slides from a PowerPoint presentation to PNG images in parallel. Since it is unsafe to use a single Presentation instance in multiple threads, we split the presentation slides into separate presentations and convert the slides to images in parallel, using each presentation in a separate thread. The following code example shows how to do this.

input_file_path = "sample.pptx"
output_file_path_template = "slide_{0}.png"
image_scale = 2

presentation = Presentation(input_file_path)

slide_count = len(presentation.slides)
slide_size = presentation.slide_size.size

conversion_tasks = []


def convert_slide(slide_index):
    # Extract slide i into a separate presentation.
    with Presentation() as slide_presentation:
        slide_presentation.slide_size.set_size(slide_size.width, slide_size.height, SlideSizeScaleType.DO_NOT_SCALE)
        slide_presentation.slides.remove_at(0)
        slide_presentation.slides.add_clone(presentation.slides[slide_index])

        slide_number = slide_index + 1
        slide = slide_presentation.slides[0]

        # Convert the slide to an image.
        with slide.get_image(image_scale, image_scale) as image:
            image_file_path = output_file_path_template.format(slide_number)
            image.save(image_file_path, ImageFormat.PNG)


with ThreadPoolExecutor() as thread_executor:
    for index in range(slide_count):
        conversion_tasks.append(thread_executor.submit(convert_slide, index))

# Wait for all tasks to complete.
for task in conversion_tasks:
    task.result()

del presentation

FAQ

Do I need to call license setup in every thread?

No. It’s enough to do it once per process/app domain before threads start. If license setup might be invoked concurrently (for example, during lazy initialization), synchronize that call because the license setup method itself is not thread-safe.

Can I pass Presentation or Slide objects between threads?

Passing “live” presentation objects between threads is not recommended: use independent instances per thread or precreate separate presentations/slide containers for each thread. This approach follows the general recommendation not to share a single presentation instance across threads.

Is it safe to parallelize export to different formats (PDF, HTML, images) provided each thread has its own Presentation instance?

Yes. With independent instances and separate output paths, such tasks typically parallelize correctly; avoid any shared presentation objects and shared I/O streams.

What should I do with global font settings (folders, substitutions) in multithreading?

Initialize all global font settings before starting the threads and do not change them during parallel work. This eliminates races when accessing shared font resources.