WPF,如何同时和真实的地多次执行异步方法?

lx0bsm1f  于 2022-11-18  发布在  其他
关注(0)|答案(1)|浏览(208)

我正在写一个WPF项目模拟不同结构(如建筑物)中的视频显示。
在这个项目中,我使用了一个特殊类型的二进制视频与bin扩展,其中的颜色存储为红色,绿色和蓝色。
我有两个方法,第一个是**“ReadDisplayBinFrames”,它有两个任务,阅读bin视频并将其显示在结构上。当然,由于这两个任务是异步的**,因此我将该方法定义为async

public async Task ReadDisplayBinFrames(Product product, bool PlayMode)
    {
        BinFile.SetPlayMode(PlayMode);

        int currentFrameNumber = 0;
        for (int i = 0; BinFile.IsPlayMode == true; i++)
        {
            for (currentFrameNumber = (int)product.LastFrameRead; currentFrameNumber <= product.BinFiles.TotalGame; currentFrameNumber++)
            {
                await Task.Run(() =>
                {
                    product.BinFiles.GetSphereColorFromBin(product.BinFiles.Read(currentFrameNumber), product.Wiring);
                    product.LastFrameRead = currentFrameNumber;
                    Debug.WriteLine($"LastFrameRead {product.LastFrameRead}");

                    product.Wiring.SetSphereColor(product.DelayPlay);
                });

                if (currentFrameNumber >= product.BinFiles.TotalGame)
                {
                    product.LastFrameRead = 0;
                }

                if (animPlayingMode == AnimPlayingMode.SerialAsync)
                {
                    BinFile.SetPlayMode(false);
                }
            }

        }
    }

由于我有一个结构列表,并且我需要能够在同时在每个结构上显示视频,因此我定义了一个名为**“PlayBin”**的方法。

private async void PlayBin()
    {
        InitBinList();

        for (int i = 0; i < Products.Count; i++)
        {
            if (animPlayingMode == AnimPlayingMode.ParallelSynchronous)
            {
                Parallel.Invoke(async () =>
                {
                    await ReadDisplayBinFrames(Products[i], true);
                    Debug.WriteLine($"LedProducts Count: {Products[i].LastFrameRead} of Product {i}");
                });
            }
            else
            {
                await ReadDisplayBinFrames(Products[i], true);
                Debug.WriteLine($"LedProducts Count: {Products[i].LastFrameRead} of Product {i}");
            }

        }
    }

当我在一个结构上显示视频时,它可以毫无问题地显示,但当我增加结构的数量(例如,6个)时,与只有一个结构的情况相比,播放速度略有下降,过了一会儿,协调性就丢失了。每个结构前进或后退几帧。
Videos Of Software Performance

mzaanser

mzaanser1#

Parallel.Invoke不支援异步方法。它必须执行简单的void委派(例如Action<T>)。这表示执行的委派永远会同步执行。
您的代码是一个很好的例子,说明了为什么将async lambda作为Action的参数传递会引入潜在的bug:因为委托的调用方需要一个Action,所以它不会对async方法执行awaitasync方法将返回Task,并且调用方将立即继续(而不是等待此Task)。
在您的情况下,Parallel.Invoke将在async方法运行完成 * 之前 * 继续。这将导致删除async上下文和意外行为。
另请注意,async方法必须始终返回TaskTask<T>(除非该方法是事件处理程序)。
应该始终使用Task.WhenAll而不是Parallel.Invoke来执行许多异步方法,并等待它们全部完成:

// Always let an async method return 'Task' or 'Task<T>' 
// and await it properly!
private async Task PlayBinAsync()
{
  InitBinList();

  if (animPlayingMode == AnimPlayingMode.ParallelSynchronous)
  {
    var runningTasks = new List<Task>();
    for (int i = 0; i < Products.Count; i++)
    {
      var runningTask = ReadDisplayBinFrames(Products[i], true);
      runningTasks.Add(runningTask);

      Debug.WriteLine($"LedProducts Count: {Products[i].LastFrameRead} of Product {i}");
    }

    await Task.WhenAll(runningTasks);
    return;
  }

  for (int i = 0; i < Products.Count; i++)
  {
    await ReadDisplayBinFrames(Products[i], true);
      runningTasks.Add(runningTask);

      Debug.WriteLine($"LedProducts Count: {Products[i].LastFrameRead} of Product {i}");
  }
}

相关问题