【问题标题】:WPF , How to execute an async method many times simultaneously and in same time?WPF , How to execute an async method many times simultaneously and in same time?
【发布时间】:2022-12-27 22:03:31
【问题描述】:

I am writing aWPF projecttosimulate videodisplay in different structures like buildings.

In this project, I use a special type of binary video with bin extension, in which the colors are stored as red, green and blue.

I have 2 methods, the first one is"ReadDisplayBinFrames", which has 2 tasks of reading bin video and displaying it on the structure. Of course, since these two tasks areasynchronous, I defined the method asasync.

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);
                }
            }

        }
    }

Since I have a list of structures and I need to be able to display a video on each of them at thesame time, I defined a method called"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}");
            }

        }
    }   

When I display the video on one structure, it is displayed without any problem, but when I increase the number of structures (for example, 6), the playback speed decreases slightly compared to the case when there was only one structure, and after a while, the coordination is lost. and each goes forward or backward a few frames.

Videos Of Software Performance

【问题讨论】:

  • Are you sure your code isn't doing something funny with currentFrameNumber ? Theirs a dependency between that and product.LastFrameRead in your for loop and the code that's executing inside and outside Task.run - have you tried getting rid of Task.Run btw ?
  • Have you seen the attached videos? Yes, I tried a lot to get rid of the async method and to do it simultaneously, but every time, nothing was displayed, or the software hung completely, or in the best case, several frames at the same time. It was displayed! Do you have any suggestions?
  • In that case there's bug(s) somewhere in your code if you're seeing these issues you mentioned - i think running things async is only clouding things.
  • A good way to help with this is to create unit tests that executes ReadDisplayBinFrames with different parameters - have you tried that ?
  • You are right, I should write a test, but I am not very professional in test writing! I was thinking of changing the ReadDisplayBinFrames method to a parallel.for method

标签: wpf async-await parallel-processing real-time parallel.for


【解决方案1】:

Parallel.Invoke does not support async methods. It expects to execute simple void delegates (e.g. Action&lt;T&gt;). This means, the executed delegates will always run synchronously.

Your code is a good piece of example why passing an async lambda as argument for an Action introduces a potential bug: because the caller of the delegate expects an Action, it won't await the async method. The async method will return the Task, and the caller will continue immediately (instead of awaiting this Task).

In your case, Parallel.Invoke will continuebeforethe async methods have run to completion. This will lead to dropping the async context and to unexpected behavior.

Also note, that an async method must always return a Task or Task&lt;T&gt; (except the method is an event handler).

Instead of Parallel.Invoke, you should always use Task.WhenAll to execute a number of asynchronous methods and wait for them all to finish:

// 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++)
    {
      Task 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}");
  }
}   

【讨论】:

    猜你喜欢
    • 2022-12-28
    • 2022-12-19
    • 2022-12-26
    • 2019-02-14
    • 2022-12-26
    • 2022-12-02
    • 2022-12-01
    • 2022-12-27
    • 2022-12-26
    相关资源
    最近更新 更多