【问题标题】:Wpf async await ui is frozenWpf async await ui被冻结
【发布时间】:2018-02-02 21:30:37
【问题描述】:
我编写了一个 WPF 桌面应用程序,并使用 async await 来保持我的 UI 更新。
它可以正常工作 5 或 6 秒,但之后 UI 冻结但后台代码运行正常。
await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
updateResultTextBox(filename);
Task.Delay(1000);
}
});
而 updateResultTextBox 是
private void updateResultTextBox(string _filename)
{
sync.Post(new SendOrPostCallback(o =>
{
result_tbx.Text += "Indexed \t" + (string)o + "\n";
result_tbx.ScrollToEnd();
}), _filename);
}
【问题讨论】:
标签:
c#
wpf
multithreading
async-await
【解决方案1】:
您的问题不太清楚。所以我不得不猜测。目前我唯一的猜测是:GUI 写入开销。
编写 GUI 并不便宜。如果您只为每个用户触发的事件执行一次,您不会注意到它。但是一旦你在一个循环中执行它——即使是在一个单独的任务或线程中运行——你会注意到它。我编写了这个简单的 Windows 窗体示例来展示差异:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
如果您启动了很多这样的任务,并且它们在此过程中突然全部返回 5-6 秒,那么您可能只是用大量的写入操作使 GUI 线程过载。
我第一次尝试多线程时就遇到了这个问题。我做了适当的多线程处理,但我仍然重载了 GUI 线程,这让它看起来我失败了。
【解决方案2】:
这段代码有一些很奇怪的地方。无论如何,这是我的两分钱:
var text = await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
return filename;
}
return string.Empty;
});
if (!string.IsNullOrEmpty(text)) {
result_tbx.Text += $"Indexed \t {text} {Environment.NewLine}";
result_tbx.ScrollToEnd();
}
仍然是代码味道...