Low Performance When Cloning Master Slides from One Presentation to Another in C#

Hi,

I’m experiencing the similar issues in our project. Here are log entries and you can see that AddClone requires sometimes several seconds:

06 Nov 2025 18:24:23.072 Masters.AddClone(sourceMasterSlide) // <- ~1sec
06 Nov 2025 18:24:22.046 Masters.AddClone(sourceMasterSlide) // <- 4+ secs
06 Nov 2025 18:24:17.434 Masters.RemoveAt(0)

This is the part of the code:

    public Presentation CreateFromSlide(ISlide slide)
    {
        var sourcePresentation = slide.Presentation;

        using var targetPresentation = new Presentation();

        // remove empty slide and its master created by default
        targetPresentation.Slides.RemoveAt(0);
        _logger.LogInformation("Slides.RemoveAt(0)");
        targetPresentation.Masters.RemoveAt(0);
        _logger.LogInformation("Masters.RemoveAt(0)");

        foreach (var sourceMasterSlide in sourcePresentation.Masters)
        {
            if (targetPresentation.Masters.Any(m => m.Name == sourceMasterSlide.Name))
            {
                continue;
            }

            targetPresentation.Masters.AddClone(sourceMasterSlide);
            _logger.LogInformation("Masters.AddClone(sourceMasterSlide)");
        }

        // ...

I noticed that @id2700 's case is also happens inside the loop, however @Professionalize.Discourse provided just the simplest example… Can any loop behaviour be involved to that performance issue?

@dslynko,
Thank you for contacting free support. We are sorry you encountered this problem. Usually, cloning master slides from one presentation to another in a loop does not cause performance issues. We need more details to investigate the case. Please share the following additional files and information:

  • The sample presentation file.
  • The name and version of the operating system on which the code was executed.
  • The .NET target platform in your application project.
  • The version of Aspose.Slides you are using.

Hey Andrej,

Sorry for the delay. Sharing you some results of my investigation.

I noticed that this happens when our app does this presentation creation, slides cloning etc in scope of parallel tasks execution via await Task.WhenAll(...) - it appeared that in that case Aspose operations might take significant time (I’ve seen numbers like ~40-50secs on our Prod environments, hosted via docker in Azure Kubernetes as a Service, to create the presentation from 900KB 1-slide pptx file). The total number of parallel tasks are usually <30-50.

I created some test app, and its visible that parallel Aspose operations have quite big fluctuations in execution time, however execution in sequence is much stable:

=== PRESENTATION FROM SLIDE ASYNC:
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=169.4348  CloneElapsedMilliseconds=161.5668
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=228.4174  CloneElapsedMilliseconds=221.2401
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=307.1624  CloneElapsedMilliseconds=304.4596
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=529.8341  CloneElapsedMilliseconds=528.6264
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=153.6606  CloneElapsedMilliseconds=146.6968
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=418.1632  CloneElapsedMilliseconds=411.1971
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=540.8681  CloneElapsedMilliseconds=533.9091
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=406.0012  CloneElapsedMilliseconds=404.8246
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=547.7089  CloneElapsedMilliseconds=546.5299
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=557.7351  CloneElapsedMilliseconds=550.0494
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=543.3715  CloneElapsedMilliseconds=534.1477
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=536.8321  CloneElapsedMilliseconds=530.1161
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=455.2743  CloneElapsedMilliseconds=446.3163
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=549.6849  CloneElapsedMilliseconds=546.4126
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=607.8707  CloneElapsedMilliseconds=600.6871
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=596.5208  CloneElapsedMilliseconds=595.3465
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=224.3431  CloneElapsedMilliseconds=216.3376
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=655.0952  CloneElapsedMilliseconds=651.5738
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=729.7427  CloneElapsedMilliseconds=719.9992
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=534.227  CloneElapsedMilliseconds=533.0622
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=576.1896  CloneElapsedMilliseconds=570.228
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=317.4492  CloneElapsedMilliseconds=316.1669
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=607.7083  CloneElapsedMilliseconds=606.4673
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=588.4483  CloneElapsedMilliseconds=587.388
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=451.9389  CloneElapsedMilliseconds=444.5965
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=639.2044  CloneElapsedMilliseconds=631.8265
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=442.5671  CloneElapsedMilliseconds=437.6482
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=787.043  CloneElapsedMilliseconds=786.0914
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=945.1685  CloneElapsedMilliseconds=944.2496
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=763.1729  CloneElapsedMilliseconds=751.0482
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=734.0482  CloneElapsedMilliseconds=733.0845

=== PRESENTATION FROM SLIDE SEQUENCE:
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=437.8042  CloneElapsedMilliseconds=410.5524
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=163.6279  CloneElapsedMilliseconds=158.534
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=149.4658  CloneElapsedMilliseconds=147.4489
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=142.5906  CloneElapsedMilliseconds=140.7279
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=166.3671  CloneElapsedMilliseconds=161.724
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=146.8236  CloneElapsedMilliseconds=142.0574
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=144.9693  CloneElapsedMilliseconds=142.2758
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=147.1785  CloneElapsedMilliseconds=143.4619
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=146.9012  CloneElapsedMilliseconds=143.3314
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=153.9749  CloneElapsedMilliseconds=149.1279
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=166.0295  CloneElapsedMilliseconds=160.7546
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=175.2911  CloneElapsedMilliseconds=167.608
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=158.2195  CloneElapsedMilliseconds=151.4624
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=147.9394  CloneElapsedMilliseconds=145.2454
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=149.2333  CloneElapsedMilliseconds=146.2061
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=148.3203  CloneElapsedMilliseconds=145.6846
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=154.2733  CloneElapsedMilliseconds=150.3233
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=153.4113  CloneElapsedMilliseconds=148.529
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=181.4137  CloneElapsedMilliseconds=176.0211
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=164.7896  CloneElapsedMilliseconds=158.6755
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=165.29  CloneElapsedMilliseconds=144.2203
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=142.104  CloneElapsedMilliseconds=137.4006
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=139.8334  CloneElapsedMilliseconds=135.5477
[ASPOSE] Presentation from slide is created. ElapsedMilliseconds=160.1446  CloneElapsedMilliseconds=155.3137

The code itself is pretty simple:

// ...
Console.WriteLine("=== PRESENTATION FROM SLIDE ASYNC:");

await Task.WhenAll(Enumerable.Range(0, 32).Select(async _ =>
{
    await PresentationFromSlideAsync();
}));

Console.WriteLine("=== PRESENTATION FROM SLIDE SEQUENCE:");

for (var i = 0; i < 32; i++)
{
    await PresentationFromSlideAsync();
}

async Task PresentationFromSlideAsync()
{
    await using var fileStream = File.OpenRead("./1-slide.pptx");
    await using var slidePresentationStream = new MemoryStream();

    await fileStream.CopyToAsync(slidePresentationStream);

    slidePresentationStream.Seek(0, SeekOrigin.Begin);

    var presTime = Stopwatch.GetTimestamp();

    using var slidePresentation = new Presentation(slidePresentationStream);

    var sourcePresentation = slide.Presentation;

    using var targetPresentation = new Presentation();

    var cloneTimeStart = Stopwatch.GetTimestamp();

    foreach (var sourceMasterSlide in sourcePresentation.Masters)
    {
        if (targetPresentation.Presentation.Masters.Any(m => m.Name == sourceMasterSlide.Name))
        {
            continue;
        }

        targetPresentation.Presentation.Masters.AddClone(sourceMasterSlide);
    }

    var slideMaster = slide.LayoutSlide.MasterSlide;

    var slideMasterInTarget = targetPresentation.Presentation.Masters
        .SingleOrDefault(m => m.Name == slideMaster.Name);

    if (slideMasterInTarget != null)
    {
        targetPresentation.Presentation.Slides.InsertClone(0, slide, slideMasterInTarget, false);
    }
    else
    {
        targetPresentation.Presentation.Slides.InsertClone(0, slide);
    }

    Console.WriteLine($"[ASPOSE] Presentation from slide is created. ElapsedMilliseconds={Stopwatch.GetElapsedTime(timeStart).TotalMilliseconds}  CloneElapsedMilliseconds={Stopwatch.GetElapsedTime(cloneTimeStart).TotalMilliseconds}");
}

I am using latest versions (Aspose.Cells:25.11.0, Aspose.Slides.NET6.CrossPlatform: 25.12.0) of Aspose nuget packages, dotnet 8/10 - no difference

@dslynko,
Thank you for the details. Could you please also share the presentation file “1-slide.pptx” you used?

1-slide.pptx.7z (19.7 KB)

Sending the file

@dslynko,
Thank you for the presentation file. I need some time to investigate the issue. I will get back to you as soon as possible.

@dslynko,
I have reproduced the problem you described. Since both scenarios call the same PresentationFromSlideAsync method and Aspose.Slides does the same work internally, the performance difference is not caused by different API behavior. The increased processing time in the fully asynchronous case is related to how .NET manages threads and CPU-intensive tasks under high parallel load (contention, scheduling, GC, etc.), so limiting the degree of parallelism to match available cores usually gives more stable timings.

Mmm… I would agree with it - if I add the semaphore to the the parallel run method, it works better, but seems parallel operations are not really effective in Aspose.

There is an interesting note: if I ran 64 tasks in sequence, and then run 64 tasks in parallel using max 8 operations simultaneously, it gives almost the same total time! (parallel sometimes even longer, ok, b/c of async overhead I suppose; I did tests on my laptop: AMD Ryzen Pro 7 CPU, 32 GB RAM, configuration: Release, Windows 11 OS).

And the more tasks I run, the longer total time for parallel operations become…

Here are results for 64, 128, 256 tasks:

=== PRESENTATION FROM SLIDE SEQUENCE:
...
[ASPOSE] From slide. ElapsedMilliseconds=37.8185  CloneElapsedMilliseconds=33.3415
[ASPOSE] From slide. ElapsedMilliseconds=30.4282  CloneElapsedMilliseconds=27.4804
[ASPOSE] From slide. ElapsedMilliseconds=27.8331  CloneElapsedMilliseconds=24.8783
=== PRESENTATION FROM SLIDE ASYNC:
...
[ASPOSE] From slide. ElapsedMilliseconds=1045.6124  CloneElapsedMilliseconds=1022.9042
[ASPOSE] From slide. ElapsedMilliseconds=1120.9866  CloneElapsedMilliseconds=1118.3301
[ASPOSE] From slide. ElapsedMilliseconds=1215.0383  CloneElapsedMilliseconds=667.0855
=== Total SEQUENCE milliseconds: 10935.9595
=== Total ASYNC milliseconds: 9526.5153
=== PRESENTATION FROM SLIDE SEQUENCE:
...
[ASPOSE] From slide. ElapsedMilliseconds=15.3091  CloneElapsedMilliseconds=14.3312
[ASPOSE] From slide. ElapsedMilliseconds=20.0109  CloneElapsedMilliseconds=18.1877
[ASPOSE] From slide. ElapsedMilliseconds=16.2789  CloneElapsedMilliseconds=14.867
=== PRESENTATION FROM SLIDE ASYNC:
...
[ASPOSE] From slide. ElapsedMilliseconds=491.6849  CloneElapsedMilliseconds=490.4524
[ASPOSE] From slide. ElapsedMilliseconds=1671.558  CloneElapsedMilliseconds=1670.2631
[ASPOSE] From slide. ElapsedMilliseconds=1671.4629  CloneElapsedMilliseconds=1670.2713
=== 128 Total SEQUENCE milliseconds: 25106.3231
=== 128 Total ASYNC milliseconds: 32748.2957
=== PRESENTATION FROM SLIDE SEQUENCE:
...
[ASPOSE] From slide. ElapsedMilliseconds=20.3652  CloneElapsedMilliseconds=19.1261
[ASPOSE] From slide. ElapsedMilliseconds=20.1624  CloneElapsedMilliseconds=18.8296
[ASPOSE] From slide. ElapsedMilliseconds=19.9699  CloneElapsedMilliseconds=18.7026
=== PRESENTATION FROM SLIDE ASYNC:
...
[ASPOSE] From slide. ElapsedMilliseconds=1934.4605  CloneElapsedMilliseconds=1004.2739
[ASPOSE] From slide. ElapsedMilliseconds=1934.7415  CloneElapsedMilliseconds=1004.3688
[ASPOSE] From slide. ElapsedMilliseconds=1978.5928  CloneElapsedMilliseconds=1976.6719
=== 256 Total SEQUENCE milliseconds: 71898.8163
=== 256 Total ASYNC milliseconds: 98164.7467

IDK… I would say something under the hood of the Aspose library prevents effective parallel works.

@andrey.potapov may be you have some thoughts/guides how parallelism can be leveraged correctly for Aspose operations?

changed code:

var semaphore = new SemaphoreSlim(8);
await Task.WhenAll(Enumerable.Range(0, 64).Select(async _ =>
{
    await semaphore.WaitAsync();
    await PresentationFromSlideAsync();
    semaphore.Release();
}));

@dslynko,
Thank you for sharing your observation results. Please note that the code example you shared earlier is not standalone and cannot be compiled as an isolated project. Please also note that the Presentation class is instantiated as the slidePresentation variable, but this variable is not used further. To continue the issue investigation on our end, could you please create and share the simplest standalone project to reproduce the problem and share your updated results?

:slight_smile: C’mon - in previous answer you mentioned that you were able to reproduce the issue. Nothing has changed in my example except adding semaphore for limiting parallelism.

@dslynko,
Yes, I removed everything unnecessary from your code, leaving only the instantiation of the presentation object and the master slide cloning, ran it, and confirmed that there is indeed a significant difference in the time required to perform the same operations with the two different approaches. However, since your code example is unusual and you provided the measurement results, I decided it would be reasonable to ask you to double-check it and provide compilable code so that our developers work with your code rather than mine, in case they are not identical.