我正在制作资源加载代码。但是,有一个问题。
var toDoList = new List<Action>();
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH1);
Console.WriteLine("Load image");
});
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH2);
Console.WriteLine("Load image");
});
// ...
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH100);
Console.WriteLine("Load image");
});
toDoList.Add(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH1);
Console.WriteLine("Load audio");
});
toDoList.Add(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH2);
Console.WriteLine("Load audio");
});
// ...
toDoList.Add(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH100);
Console.WriteLine("Load audio");
});
Console.WriteLine("Parallel Load Start");
Parallel.ForEach(toDoList, toDo => {
toDo();
});
Console.WriteLine("Parallel Load End");
我想让Parallel等待所有LoadAsync函数完成。但是,由于异步Action委托,我没有等待。它表明了
并行加载开始
加载音频
加载音频
载入图片
加载音频
载入图片
...
加载音频
平行负载端
载入图片
载入图片
载入图片
...
由于它是Win2D的一部分,因此没有同步加载图像的方法。 (= WinRT API)
我了解为什么所有磁盘I / O任务都必须是异步方法。
但是,以上代码不是在UI线程上运行,而是在自定义线程上运行。因此,它不需要运行异步。
您可以认为,由于异步方法,并行是无用的。但是,正如您所看到的,toDoValues具有异步(Win2D)和同步(音频)。需要并行才能有效加载音频文件。
如何让Parallel等待所有资源加载完毕?
答案 0 :(得分:3)
需要并行才能有效加载音频文件。
嗯,Parallel
是执行并行操作的一种方法。但是您的代码当前正在混合使用CPU约束的操作和异步操作,并尝试使用Parallel
将它们组合在一起,Task.Run
仅用于 。这就是为什么它不能很好地工作的原因。
更好的方法是使用Parallel
而不是Task.WhenAll
将CPU绑定的操作推送到线程池中。然后,您可以将它们作为异步对象进行处理(从UI线程的角度来看),然后使用var toDoList = new List<Func<Task>>();
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH1);
Console.WriteLine("Load image");
});
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH2);
Console.WriteLine("Load image");
});
// ...
toDoList.Add(async () =>
{
await CanvasBitmap.LoadAsync(PATH100);
Console.WriteLine("Load image");
});
toDoList.Add(() => Task.Run(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH1);
Console.WriteLine("Load audio");
}));
toDoList.Add(() => Task.Run(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH2);
Console.WriteLine("Load audio");
}));
// ...
toDoList.Add(() => Task.Run(() =>
{
AudioSystem.Instance.Load(AUDIO_PATH100);
Console.WriteLine("Load audio");
}));
Console.WriteLine("Concurrent Load Start");
var tasks = toDoList.Select(toDo => toDo()).ToList();
Console.WriteLine("Concurrent Load Started");
await Task.WhenAll(tasks);
Console.WriteLine("Concurrent Load End");
将它们与自然异步的I / O操作结合起来。
使用示例代码,如下所示:
Rmisc
答案 1 :(得分:1)
您需要使用WhenAll
。
Console.WriteLine("Parallel Load Start");
Parallel.ForEach(toDoList, toDo => {
toDo();
});
await Task.WhenAll(toDoList); // Next line will be executed when all tasks are completed,
Console.WriteLine("Parallel Load End");