Ben*_*ggs 5 c# asynchronous async-await
我在C#.NET应用程序中有关于async\await的问题.我实际上试图在基于Kinect的应用程序中解决这个问题,但为了帮助我说明,我已经制作了这个类似的例子:
想象一下,我们有一个名为timer1的Timer,它设置了Timer1_Tick事件.现在,我对该事件采取的唯一操作是使用当前日期时间更新UI.
private void Timer1_Tick(object sender, EventArgs e)
{
txtTimerValue.Text = DateTime.Now.ToString("hh:mm:ss.FFF", CultureInfo.InvariantCulture);
}
Run Code Online (Sandbox Code Playgroud)
这很简单,我的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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我遇到问题的时候.计算素数的密集方法会阻止事件处理程序运行 - 因此我的计时器文本框现在每30秒左右更新一次.
我的问题是,如何在遵守以下规则的同时解决这个问题:
我试图用async/await做一些事情并让我的素数计算函数返回一个Task>但是还没有设法解决我的问题.Timer1_Tick事件中的await调用似乎仍然阻塞,阻止了进一步执行处理程序.
任何帮助都会很高兴 - 我非常擅长接受正确的答案:)
更新:我非常感谢@sstan能够为这个问题提供一个简洁的解决方案.但是,我在将这个应用到基于Kinect的真实情况时遇到了麻烦.由于我有点担心这个问题太具体,我在这里发布了一个新的问题:Kinect Frame Arrived Asynchronous
所以你想启动一个任务而不等待结果。当任务完成计算后,它应该更新 UI。
您的 UI 在长时间操作期间没有响应的原因是您没有声明事件处理程序异步。查看结果的最简单方法是为按钮创建事件处理程序:
同步 - UI 在执行期间被阻止:
private void Button1_clicked(object sender, EventArgs e)
{
List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
PrintPrimeNumbersToScreen(primeNumbersList);
}
Run Code Online (Sandbox Code Playgroud)
异步 - UI 在执行期间响应:
private async void Button1_clicked(object sender, EventArgs e)
{
List<int> primeNumbersList = await Task.Run( () => WorkOutFirstNPrimeNumbers(500));
PrintPrimeNumbersToScreen(primeNumbersList);
}
Run Code Online (Sandbox Code Playgroud)
注意差异:
笔记:
<TResult> 而不是 TResult。<TResult> 是一个 TResult。<TResult>。问题是你的计时器比你的计算快。如果前面的计算还没有完成就报告了新的tick,你想要什么?
(1) 启动任务,但不要等待它。
private void Button1_clicked(object sender, EventArgs e)
{
Task.Run ( () =>
{ List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
PrintPrimeNumbersToScreen(primeNumbersList);
});
}
Run Code Online (Sandbox Code Playgroud)
(2) 如果任务仍然繁忙,则忽略该勾号:
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);
});
}
}
Run Code Online (Sandbox Code Playgroud)
(3)启动一个连续计算的任务
private void StartTask(CancellationToken token)
{
Task.Run( () =>
{
while (!token.IsCancelRequested)
{
List<int> primeNumbersList = WorkOutFirstNPrimeNumbers(500);
PrintPrimeNumbersToScreen(primeNumbersList);
}
})
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
689 次 |
| 最近记录: |