gpt4 book ai didi

c# - 异步等待以保持事件触发

转载 作者:太空狗 更新时间:2023-10-29 23:13:51 25 4
gpt4 key购买 nike

我对 C# .NET 应用程序中的 async\await 有疑问。我实际上是在尝试在基于 Kinect 的应用程序中解决这个问题,但为了帮助说明,我制作了这个类似的示例:

假设我们有一个定时器,称为 timer1,它设置了一个 Timer1_Tick 事件。现在,我对该事件采取的唯一操作是使用当前日期时间更新 UI。

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

这很简单,我的 UI 每百分之几秒更新一次,我可以愉快地看着时间流逝。

现在假设我还想用同样的方法计算前 500 个质数:

 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 秒左右更新一次。

我的问题是,如何在遵守以下规则的同时解决这个问题:

  • 我需要我的 UI 计时器文本框像以前一样流畅,可能是通过将密集的素数计算推到不同的线程。我想,这将使事件处理程序像以前一样频繁地运行,因为阻塞语句不再存在。
  • 每次素数计算函数完成时,都会将结果写入屏幕(使用我的 PrintPrimeNumbersToScreen() 函数)并且应该立即再次启动,以防这些素数当然发生变化。

我尝试用 async/await 做一些事情并让我的质数计算函数返回一个 Task> 但没能解决我的问题。 Timer1_Tick 事件中的 await 调用似乎仍然阻塞,阻止处理程序的进一步执行。

任何帮助将不胜感激 - 我非常擅长接受正确答案:)

更新:我非常感谢@sstan 能够为这个问题提供一个巧妙的解决方案。但是,我无法将其应用于我真实的基于 Kinect 的情况。由于我有点担心这个问题过于具体,因此我已将后续问题作为新问题发布在这里:Kinect Frame Arrived Asynchronous

最佳答案

可能不是最好的解决方案,但它会起作用。您可以创建 2 个独立的计时器。您的第一个计时器的 Tick 事件处理程序只需要处理您的 txtTimerValue 文本框。它可以保持原来的样子:

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

对于您的第二个计时器的 Tick 事件处理程序,定义 Tick 事件处理程序如下:

private async void Timer2_Tick(object sender, EventArgs e)
{
timer2.Stop(); // this is needed so the timer stops raising Tick events while this one is being awaited.

txtPrimeAnswers.Text = await Task.Run(() => {
List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
return ConvertPrimeNumbersToString(primeNumbersList);
});

timer2.Start(); // ok, now we can keep ticking.
}

private string ConvertPrimeNumbersToString(List<int> primeNumbersList)
{
var primeNumberString = new StringBuilder();
foreach (int primeNumber in primeNumbersList)
{
primeNumberString.AppendFormat("The value {0} is prime \r\n", primeNumber);
}
return primeNumberString.ToString();
}

// the rest of your methods stay the same...

您会注意到我将您的 PrintPrimeNumbersToScreen() 方法更改为 ConvertPrimeNumbersToString()(其余部分保持不变)。更改的原因是您确实希望最大限度地减少在 UI 线程上完成的工作量。所以最好从后台线程准备字符串,然后在 UI 线程上对 txtPrimeAnswers 文本框做一个简单的赋值。

编辑:另一种可以与单个计时器一起使用的替代方法

这是另一个想法,但只有一个计时器。这里的想法是您的 Tick 偶数处理程序将保持定期执行并每次更新您的计时器值文本框。但是,如果素数计算已经在后台进行,事件处理程序将跳过该部分。否则,它将开始素数计算并在完成后更新文本框。

// global variable that is only read/written from UI thread, so no locking is necessary.
private bool isCalculatingPrimeNumbers = false;

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

if (!this.isCalculatingPrimeNumbers)
{
this.isCalculatingPrimeNumbers = true;
try
{
txtPrimeAnswers.Text = await Task.Run(() => {
List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
return ConvertPrimeNumbersToString(primeNumbersList);
});
}
finally
{
this.isCalculatingPrimeNumbers = false;
}
}
}

private string ConvertPrimeNumbersToString(List<int> primeNumbersList)
{
var primeNumberString = new StringBuilder();
foreach (int primeNumber in primeNumbersList)
{
primeNumberString.AppendFormat("The value {0} is prime \r\n", primeNumber);
}
return primeNumberString.ToString();
}

// the rest of your methods stay the same...

关于c# - 异步等待以保持事件触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32035816/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com