UWP - 如何启动并行运行的多个任务?

Posted

技术标签:

【中文标题】UWP - 如何启动并行运行的多个任务?【英文标题】:UWP - How to start multiple tasks running in parallel? 【发布时间】:2020-11-17 04:31:00 【问题描述】:

我有一个应用程序,我可以在其中选择多个 (300-500) 图像,然后创建一个视频,其中每个图像都是一个帧。为了将这些图像加载到合成中进行播放,我需要先将它们转换并保存到临时内存中,然后才能加载它们。此转换/保存过程需要一些时间,我正在努力寻找加快任务速度的方法。

让这个转换任务的多个实例并行执行的好方法是什么?目前,在进行转换时,CPU 使用率很低 (4%-6%)。

这是我希望它的工作方式:

    用户选择多个图像文件

    在临时存储中创建一个文件夹

    创建多个图像转换/保存任务并并行运行。

    转换保存完成后,将临时存储文件夹中的所有转换后的图像都选中并加载到合成中进行播放。

这是我现在拥有的:

private async Task OpenImageSequence(IReadOnlyList<StorageFile> files)


    destFolder = await ApplicationData.Current.TemporaryFolder.CreateFolderAsync(NameNoExt, CreationCollisionOption.GenerateUniqueName);
    var composition = new MediaComposition();

    foreach (StorageFile file in files)
    
        CreateImage(file);
    

    IReadOnlyList<StorageFile> fileList = await destFolder.GetFilesAsync();

    foreach (StorageFile imgFile in fileList)
    
        var clip = await MediaClip.CreateFromImageFileAsync(imgFile, TimeSpan.FromSeconds(frameIncrement));
        composition.Clips.Add(clip);
    

    MediaStreamSource newImageSequence = composition.GenerateMediaStreamSource(defaultProfile);
    windowsSource = MediaSource.CreateFromMediaStreamSource(newImageSequence);



private async Task CreateImage(StorageFile file)

    var stream = await file.OpenStreamForReadAsync();
    
    //....Image Conversion Code....//

    var destFile = await destFolder.CreateFileAsync("exrConvert.png", Windows.Storage.CreationCollisionOption.GenerateUniqueName);

    await canvas.SaveAsync(destFile.Path.ToString(), CanvasBitmapFileFormat.Png);

基本上,我希望有尽可能多的 CreateImage 任务实例并行运行。关于我如何去做这件事有什么想法吗?

我尝试了以下 10 张图片的选择,但这些图片似乎没有被并行处理:

    Task t1 = CreateImage(files.ElementAt(0));
    Task t2 = CreateImage(files.ElementAt(1));
    Task t3 = CreateImage(files.ElementAt(2));
    Task t4 = CreateImage(files.ElementAt(3));
    Task t5 = CreateImage(files.ElementAt(4));
    Task t6 = CreateImage(files.ElementAt(5));
    Task t7 = CreateImage(files.ElementAt(6));
    Task t8 = CreateImage(files.ElementAt(7));
    Task t9 = CreateImage(files.ElementAt(8));
    Task t10 = CreateImage(files.ElementAt(9));

    await Task.WhenAll(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);

感谢您提供的任何帮助!

【问题讨论】:

您的代码受 IO 限制,而不是 CPU 限制,因此如果您做错了什么,您的 CPU 利用率只会很高。您需要查看您正在读取/写入文件的位置的利用率。大多数文件存储设备不能很好地并行化,因此您不太可能看到并行化带来的显着改进(实际上可能会看到显着的退化)。 与 Servy 的评论相关,提高速度的最佳选择可能是权衡内存。即,将流保存在内存中,而不是使用临时目录。 感谢两位为我澄清问题。我一直将流保存在内存中,但在创建媒体组合时一直遇到问题。不过,我会进一步追求这一点,因为这似乎是最好的前进道路。如果我将流保存在内存中,图像转换任务的并行化是否有好处,因为不再存在存储设备性能的瓶颈? 您提到“但图像似乎没有被并行处理”,它仍然是逐个任务处理还是 CreateImage 方法没有实际运行? 能否提供minimal reproducible example? 【参考方案1】:

要让多个任务并行运行,每个任务都必须组合为后台任务。所以你需要使用Task.Run() 什么的。具有 Task 返回类型的普通异步函数不会产生后台任务。

//foreach (StorageFile file in files)
//
//    await CreateImage(file);
//
var tasks_in_background_thread = files.Select(file => Task.Run(async () =>

    await CreateImage(file);
));
await Task.WhenAll(tasks_in_background_thread);

【讨论】:

以上是关于UWP - 如何启动并行运行的多个任务?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UWP 的后台每天午夜运行一些代码?

如何在基于 C# 的 Windows 服务中处理以不同时间间隔并行运行的多个任务?

并发与并行的区别

以半并行方式运行多个任务

如何从 bash 脚本并行运行多个程序?

如何并行调试 Windows UWP 应用程序?