【发布时间】:2020-10-10 18:32:49
【问题描述】:
我正在尝试让一段代码运行得更快。代码已经在使用 async/await。但是还是很慢。
所以我尝试更改我的 foreach 以使用新的 IAsyncEnumerable。但是,我从中获得了 0 性能。它似乎按顺序运行代码。这让我很惊讶。我认为await foreach 会在自己的线程中运行每次迭代。
这是我加快代码速度的尝试。
var bag = new ConcurrentBag<IronPdf.PdfDocument>(); // probably don't need a ConcurrentBag
var foos = _dbContext.Foos;
await foreach (var fooPdf in GetImagePdfs(foos))
{
bag.Add(fooPdf);
}
private async IAsyncEnumerable<IronPdf.PdfDocument> GetImagePdfs(IEnumerable<Foo> foos)
{
foreach (var foo in foos)
{
var imagePdf = await GetImagePdf(foo);
yield return imagePdf;
}
}
private async Task<IronPdf.PdfDocument> GetImagePdf(Foo foo)
{
using var imageStream = await _httpService.DownloadAsync(foo.Id);
var imagePdf = await _pdfService.ImageToPdfAsync(imageStream);
return imagePdf;
}
using IronPdf;
public class PdfService
{
// this method is quite slow
public async Task<PdfDocument> ImageToPdfAsync(Stream imageStream)
{
var imageDataURL = Util.ImageToDataUri(Image.FromStream(imageStream));
var html = $@"<img style=""max-width: 100%; max-height: 70%;"" src=""{imageDataURL}"">";
using var renderer = new HtmlToPdf(new PdfPrintOptions()
{
PaperSize = PdfPrintOptions.PdfPaperSize.A4,
});
return await renderer.RenderHtmlAsPdfAsync(html);
}
}
我也试过Parallel.ForEach
Parallel.ForEach(foos, async foo =>
{
var imagePdf = await GetImagePdf(foo);
bag.Add(imagePdf);
});
但是我一直在读到我不应该对它使用异步,所以不知道该怎么做。这样做时 IronPdf 库也会崩溃。
【问题讨论】:
-
“它似乎是按顺序运行代码”愿意分享是什么让您得出这个结论?
-
我在其中放置了一些日志消息以打印它何时开始获取
foo.Id以及何时将其添加到包中。顺序是:开始 1,完成 1,开始 2,完成 2,等等 -
var tasks = _dbContext.Foos.Select(x => GetImagePdfs(x)); await Task.WhenAll(Tasks); -
@MichaelRandall 感谢它的工作原理。我预计
await foreach会这样工作,但显然误解了它的用途 -
作为旁注,如果我听起来很迂腐,很抱歉,async/await 与使事情运行得更快没有直接关系。如果您有许多操作要做并且想要更快地完成,解决方案是同时运行,而不是异步。单独从同步切换到异步几乎不会产生任何影响。从顺序切换到并发将改变世界。这是一个相关的问题:What is the difference between concurrency, parallelism and asynchronous methods?
标签: c# async-await parallel-processing ironpdf