【问题标题】:Asynchronous Code Is Not Faster than the Synchronous Version异步代码不比同步版本快
【发布时间】:2020-07-31 18:17:04
【问题描述】:

我对异步编程不是很有经验,所以请原谅我的无知。

我正在尝试异步生成 PDFS 列表以提高性能。

但是,无论是异步还是同步,代码的运行方式都是一样的:

Parallel Test MS: 10452
Async Test MS: 9971
Sync Test MS: 10501

有什么明显的我做错了,还是图书馆?我正在使用以下文档:https://ironpdf.com/docs/questions/async/

主要:

static async Task Main(string[] args)
        {
            var html = @"<h1>Hello World!</h1><br><p>This is IronPdfss.</p>";
            Stopwatch stopwatch = new Stopwatch();
            List<PdfDocument> pdfDocuments = new List<PdfDocument>();
            List<string> htmlStrings = new List<string>();
            for (int i = 0; i < iterations; i++)
                htmlStrings.Add(html);

            stopwatch.Start();
            Parallel.ForEach(htmlStrings, htmlString =>
            {
                var document = RenderPdf(htmlString);
                pdfDocuments.Add(document);
            });
            stopwatch.Stop();
            Console.WriteLine($"Parallel Test MS: {stopwatch.ElapsedMilliseconds}");

            stopwatch.Restart();
            var tasks = htmlStrings.Select(async h =>
            {
                var response = await RenderPdfAsync(h);
                pdfDocuments.Add(response);
            });
            await Task.WhenAll(tasks);
            stopwatch.Stop();
            Console.WriteLine($"Async Test MS: {stopwatch.ElapsedMilliseconds}");

            stopwatch.Restart();
            foreach (string h in htmlStrings)
            {
                var document = RenderPdf(h);
                pdfDocuments.Add(document);
            }
            stopwatch.Stop();
            Console.WriteLine($"Sync Test MS: {stopwatch.ElapsedMilliseconds}");

            Console.ReadLine();
        }

辅助方法:

private static async Task<IronPdf.PdfDocument> RenderPdfAsync(string Html, IronPdf.PdfPrintOptions PrintOptions = null)
{
    return await Task.Run(() => RenderPdf(Html, PrintOptions));
}
private static IronPdf.PdfDocument RenderPdf(string Html, IronPdf.PdfPrintOptions PrintOptions = null)
{
    var Renderer = new IronPdf.HtmlToPdf();
    if (PrintOptions != null)
    {
        Renderer.PrintOptions = PrintOptions;
    }
    PdfDocument Pdf = Renderer.RenderHtmlAsPdf(Html);
    return Pdf;
}

【问题讨论】:

  • 顺便说一句,这并不能真正解决您的性能问题,Parallel.ForEach 将导致竞争条件。您的列表 pdfDocuments 可能会同时写入多次。

标签: c# .net ironpdf


【解决方案1】:
private static async Task<IronPdf.PdfDocument> RenderPdfAsync(string Html, IronPdf.PdfPrintOptions PrintOptions = null)
{
    return await Task.Run(() => RenderPdf(Html, PrintOptions));
}

这就是通常所说的“假异步”。这是一种具有异步签名的方法,它并不是真正的异步。它只是在线程池线程上运行的同步工作。因此,“异步”代码的行为与并行代码非常相似:它在线程池线程上运行每个渲染。

在这种情况下,操作受 CPU 限制,而不是 I/O 限制,因此同步或并行代码是正确的方法。例如,我认为 Parallel LINQ 是最好的方法。你不会想在这里使用异步代码。

您的时间安排的奇怪之处在于并行代码并不比同步代码快。对此的一种解释是 PDF 呈现已经并行,因此额外的并行性无济于事。另一种解释是某些东西将您的应用程序限制为只能在单个 CPU 内核上运行。

【讨论】:

    【解决方案2】:

    看这里:

            var tasks = htmlStrings.Select(async h =>
            {
                var response = await RenderPdfAsync(h);
                pdfDocuments.Add(response);
            });
            await Task.WhenAll(tasks);
    

    您正在Select 中等待,所以您一次只做一个。尝试做这样的事情:

            var tasks = htmlStrings.Select(h =>
            {
                return RenderPdfAsync(h);
            });
            await Task.WhenAll(tasks);
            foreach(var t in tasks){ pdfDocuments.Add(await t); }
    

    请记住,您已经在上面使用了适当的并行库 (Parallel.ForEach),并且为了保持一致,您可能也应该在此处使用该模式。

    【讨论】:

    • 嗯,这个代码似乎没有任何区别,安迪。多么奇怪。
    • 这不会改变操作是否并行运行。在任何一种情况下,这两个 sn-ps 的行为都是相同的。两者不同的唯一方式是,第二个使用任务的返回值,第一个直接添加到列表中,如this post 中所述。该方法的时间与 OP 中的 Parallel.ForEach 调用相当,这一事实表明该操作的某些潜在行为是不可并行的。
    • @DragonMasa -- 我以前用过 IronPDF,它是一个巨大的 CPU 猪。瓶颈可能在于 IronPDF/CPU 而不是并行化。
    • @Andy 你对提高性能有什么建议吗?
    • @DragonMasa -- 听起来很刺耳,你可以在你的电脑上安装一个更好的处理器。不幸的是,无论我使用什么技巧,我都没有让它更快。我尝试了很多 PDF 转换器,我相信我最终选择了SelectPdf,但我不相信结果会好得多。它们基本上都使用相同的后端将 HTML 处理成 PDF 文档。
    【解决方案3】:

    截至 2021 年 9 月 - IronPDF 的 2021.9 版本在并行性方面比以往任何时候都好得多。

    真正的多线程在 Web 和桌面应用程序开发方面对我的团队来说效果很好。

    此版本在 nuget 上可用:https://www.nuget.org/packages/IronPdf/

    在 IronPdf 版本 2021.9.3737 上测试......

    C# 和 VB 代码示例:

    • IronPDF + 异步:https://ironpdf.com/examples/async/

    • IronPDF + System.Threading:https://ironpdf.com/examples/threading/

    • IronPDF + Parallel.ForEach:https://ironpdf.com/examples/parallel/

       using System;
       using System.Collections.Generic;
       using System.Linq;
       using System.Threading.Tasks;
       using IronPdf;
      
      
       var Renderer = new IronPdf.ChromePdfRenderer();
      
       var htmls = new List<string>()  { "<h1>Html#1</h1>", "<h1>Html#2</h1>", "<h1>Html#3</h1>" };
      
       Parallel.ForEach(htmls, (html) => 
       {
               var pdfDocument = Renderer.RenderHtmlAsPdfAsync(html).Result;
               // do something with each pdfDocument  
       });
      

    【讨论】:

      【解决方案4】:

      这一行

      var response = await RenderPdfAsync(h);
      

      应该是这样的

      var task = RenderPdfAsync(h);
      

      然后一起等待所有任务

      【讨论】:

        猜你喜欢
        • 2019-09-25
        • 1970-01-01
        • 2021-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-24
        相关资源
        最近更新 更多