异步恭候保持事件触发 [英] Async Await to Keep Event Firing

查看:80
本文介绍了异步恭候保持事件触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于异步\\问题等待在C#.NET应用程序。实际上,我试图解决在Kinect的基于应用程序,但帮我说明这个问题,我制作的这个类似的例子:

I have a question about async\await in a C# .NET app. I'm actually trying to solve this problem in a Kinect based application but to help me illustrate, I've crafted this analogous example:

假设我们有一个定时器,定时器称为具有Timer1_Tick事件成立。现在,我对这项赛事的唯一作用是更新与当前日期和时间的用户界面。

Imagine that we have a Timer, called timer1 which has a Timer1_Tick event set up. Now, the only action I take on that event is to update the UI with the current date time.

 private void Timer1_Tick(object sender, EventArgs e)
    {
        txtTimerValue.Text = DateTime.Now.ToString("hh:mm:ss.FFF", CultureInfo.InvariantCulture);
    }

这是很简单的,我的UI更新秒每百分之几,我可以高兴地看着时间匆匆而过。

This is simple enough, my UI updates every few hundredths of seconds and I can happily watch time go by.

现在想象,我也想在像这样同样的方法也算第500素数:

Now imagine that I also want to also calculate the first 500 prime numbers in the same method like so:

 private void Timer1_Tick(object sender, EventArgs e)
    {
        txtTimerValue.Text = DateTime.Now.ToString("hh:mm:ss.FFF", CultureInfo.InvariantCulture);
        List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
        PrintPrimeNumbersToScreen(primeNumbersList);
    }

    private List<int> WorkOutFirstNPrimeNumbers(int n)
    {
        List<int> primeNumbersList = new List<int>();
        txtPrimeAnswers.Clear();
        int counter = 1;
        while (primeNumbersList.Count < n)
        {
            if (DetermineIfPrime(counter))
            {
                primeNumbersList.Add(counter);

            }
            counter++;
        }

        return primeNumbersList;
    }

    private bool DetermineIfPrime(int n)
    {
        for (int i = 2; i < n; i++)
        {
            if (n % i == 0)
            {
                return false;
            }
        }
        return true;
    }
    private void PrintPrimeNumbersToScreen(List<int> primeNumbersList)
    {
        foreach (int primeNumber in primeNumbersList)
        {
            txtPrimeAnswers.Text += String.Format("The value {0} is prime \r\n", primeNumber);
        }
    }

这是当我遇到问题。一个计算素数块从正在运行的事件处理程序的强化方法 - 。因此,我的定时器文本框中现在只能每30秒更新左右。

This is when I experience the problem. The intensive method that calculates the prime numbers blocks the event handler from being run - hence my timer text box now only updates every 30 seconds or so.

我的问题是,我怎么能解决这个一边观察以下规则:

My question is, how can I resolve this while observing the following rules:


  • 我需要我的UI定时器​​文本框那样顺利,因为它以前,可能是通过推动集约化素数计算,以不同的线程。我猜,这将使该事件处理程序尽可能频繁地运行之前,因为阻塞语句就不再出现了。

  • 每次素数计算功能完成时,它的结果(使用我PrintPrimeNumbersToScreen()函数)被写入到屏幕和它应当再次立即开始,以防万一当然那些素数的变化。

我试图做一些事情异步/等待,使我的素数计算函数返回一个任务>,但没有设法解决我的问题。在Timer1_Tick事件中的await调用似乎仍然阻拦,preventing处理程序的进一步执行。

I have tried to do some things with async/await and making my prime number calculation function return a Task> but haven't managed to resolve my problem. The await call in the Timer1_Tick event still seems to block, preventing further execution of the handler.

任何帮助将是非常乐意AP preciated - 我很善于接受正确的答案:)

Any help would be gladly appreciated - I'm very good at accepting correct answers :)

更新:我非常感谢@sstan谁能够提供很好地解决了这个问题。然而,我在应用此我真正的基于Kinect的局势的麻烦。由于我有点担心使这个问题太具体,我已经张贴了新的问题在这里的跟进:的 Kinect的帧到达异步

Update: I am very grateful to @sstan who was able to provide a neat solution to this problem. However, I'm having trouble applying this to my real Kinect-based situation. As I am a little concerned about making this question too specific, I have posted the follow up as a new question here: Kinect Frame Arrived Asynchronous

推荐答案

所以,你要开始一个任务,而无需等待结果。当任务完成计算应更新UI。

So you want to start a Task without waiting for the result. When the task has finished calculating it should update the UI.

究其原因,你的UI是不是漫长的诉讼过程中响应是因为你没有声明事件处理程序异步。看到这样的结果,最简单的方法是通过一个按钮创建一个事件处理程序:

The reason that your UI isn't responsive during the long action is because you didn't declare your event handler async. The easiest way to see the result of this is by creating an event handler for a button:

同步 - UI在执行过程中阻止:

private void Button1_clicked(object sender, EventArgs e)
{
    List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
    PrintPrimeNumbersToScreen(primeNumbersList);
}

异步 - UI执行过程中响应:

private async void Button1_clicked(object sender, EventArgs e)
{
    List<int> primeNumbersList = await Task.Run( () => WorkOutFirstNPrimeNumbers(500));
    PrintPrimeNumbersToScreen(primeNumbersList);
}

请注意区别:


  • 该函数声明异步

  • 作为调用的功能,任务是用Task.Run启动

  • 的等待的语句可以确保您的UI线程返回并保持处理所有UI请求。

  • 一旦任务完成,UI线程继续与的await的一个部分。

  • 的的await的值是WorkOutFirstNPrimeNumber函数的返回

请注意:


  • 通常你会看到异步函数返回一个任务,而不是无效,任务&LT; TResult >而不是TResult

  • 的等待任务是一个空白,等待任务&LT; TResult >是TResult

  • 要启动一个函数作为一个单独的任务使用Task.Run(()=> MyFunction的(...))

  • Task.Run的返回是一个awaitable任务。

  • 当你想使用的await,你必须声明你的函数异步,从而返回任务或任务&LT; TResult >

  • 所以,你的来电者必须是异步等等。

  • 可能返回void唯一的异步功能是事件处理程序。

  • normally you'll see async functions return a Task instead of void and Task<TResult> instead of TResult.
  • The await Task is a void and await Task<TResult> is a TResult.
  • To start a function as a separate task use Task.Run ( () => MyFunction(...))
  • The return of Task.Run is an awaitable Task.
  • Whenever you want to use await, you'll have to declare your function async, and thus return Task or Task<TResult>.
  • So your callers have to be async and so forth.
  • The only async function that may return void is the event handler.

问题是,你的计时器比你更快的计算。你想要什么,如果当previous计算还没有完成。据悉新的蜱

The problem is that your timer is faster than your calculations. What do you want if a new tick is reported when the previous calculations are not finished


  1. 好歹开始新的计算。这可能会导致大量的线程在同一时间做计算。

  2. 忽略打勾,直到没有计算都在忙着

  3. 您也可以选择让只有一个任务做了计算,并尽快为他们完成启动它们。在这种情况下,计算连续运行

(1)启动任务,但不要等待它。

(1) Start the Task, but do not await for it.

private void Button1_clicked(object sender, EventArgs e)
{
    Task.Run ( () =>
    {    List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
        PrintPrimeNumbersToScreen(primeNumbersList);
    }); 
}

(2)忽略打勾如果任务仍然忙:

(2) ignore the tick if the task is still busy:

Task primeCalculationTask = null;
private void Button1_clicked(object sender, EventArgs e)
{
    if (primeCalculationTask == null || primeCalculationTask.IsCompleted)
    {   // previous task finished. Stat a new one
        Task.Run ( () =>
        {    List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
            PrintPrimeNumbersToScreen(primeNumbersList);
        }); 
    }
}

(3)启动了连续计算任务

(3) Start a task that calculates continuously

private void StartTask(CancellationToken token)
{
    Task.Run( () =>
    {
        while (!token.IsCancelRequested)
        {
            List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
            PrintPrimeNumbersToScreen(primeNumbersList);
        }
     })
 }

这篇关于异步恭候保持事件触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆