C# Async await-避免阻塞UI是正确的想法吗?
我认为使用await/async是确保响应性UI的最佳方法。但我似乎做错了什么,因为我的应用程序无论如何都会冻结 我尝试做什么: 按钮已启动,应等待长时间操作C# Async await-避免阻塞UI是正确的想法吗?,c#,asynchronous,C#,Asynchronous,我认为使用await/async是确保响应性UI的最佳方法。但我似乎做错了什么,因为我的应用程序无论如何都会冻结 我尝试做什么: 按钮已启动,应等待长时间操作 public async Task CmdLoadExcel() { // läd die excel datei string[] excelFiles = this.GetExcelFiles(); ExcelLoader eloader = new ExcelLoader(); await eloader.
public async Task CmdLoadExcel()
{
// läd die excel datei
string[] excelFiles = this.GetExcelFiles();
ExcelLoader eloader = new ExcelLoader();
await eloader.StartLoading(excelFiles);
foreach (DataSet elem in eloader.Tables)
{
this.ActivateItem(new ExcelViewModel(elem) { DisplayName = elem.DataSetName });
}
}
推出的课程:
public async Task StartLoading(string[] files)
{
foreach (string file in files)
{
Stopwatch swatch = new Stopwatch();
swatch.Start();
System.Threading.Thread.Sleep(5000);
FileInfo finfo = new FileInfo(file);
using (ExcelPackage package = new ExcelPackage(finfo))
{
// very long operation
}
} // For Each
} // StartLoading
它只是在睡眠时停止,我不确定我做错了什么。用async和wait标记方法本身并不能做任何事情。您需要等待一项任务: 这将有助于:
public async Task StartLoading(string[] files)
{
return Task.Run(() =>
{
foreach (string file in files)
{
Stopwatch swatch = new Stopwatch();
swatch.Start();
System.Threading.Thread.Sleep(5000);
FileInfo finfo = new FileInfo(file);
using (ExcelPackage package = new ExcelPackage(finfo))
{
// very long operation
}
} // For Each
};
} // StartLoading
用async和await标记方法本身并没有任何作用。您需要等待一项任务: 这将有助于:
public async Task StartLoading(string[] files)
{
return Task.Run(() =>
{
foreach (string file in files)
{
Stopwatch swatch = new Stopwatch();
swatch.Start();
System.Threading.Thread.Sleep(5000);
FileInfo finfo = new FileInfo(file);
using (ExcelPackage package = new ExcelPackage(finfo))
{
// very long operation
}
} // For Each
};
} // StartLoading
问题是,令人吃惊的任务本身并不是异步的。您可以使用以下代码修复此问题:
public Task StartLoading(string[] files)
{
return Task.Factory.StartNew(() =>
{
foreach (string file in files)
{
Stopwatch swatch = new Stopwatch();
swatch.Start();
System.Threading.Thread.Sleep(5000);
FileInfo finfo = new FileInfo(file);
using (ExcelPackage package = new ExcelPackage(finfo))
{
// very long operation
}
} // For Each
});
} // StartLoading
然后您可以按如下方式使用代码:
public Task CmdLoadExcel()
{
// läd die excel datei
string[] excelFiles = this.GetExcelFiles();
ExcelLoader eloader = new ExcelLoader();
var task = eloader.StartLoading(excelFiles);
return task.ContinueWith(t =>
{
foreach (DataSet elem in eloader.Tables)
{
this.ActivateItem(new ExcelViewModel(elem) { DisplayName = elem.DataSetName });
}
});
}
问题是,令人吃惊的任务本身并不是异步的。您可以使用以下代码修复此问题:
public Task StartLoading(string[] files)
{
return Task.Factory.StartNew(() =>
{
foreach (string file in files)
{
Stopwatch swatch = new Stopwatch();
swatch.Start();
System.Threading.Thread.Sleep(5000);
FileInfo finfo = new FileInfo(file);
using (ExcelPackage package = new ExcelPackage(finfo))
{
// very long operation
}
} // For Each
});
} // StartLoading
然后您可以按如下方式使用代码:
public Task CmdLoadExcel()
{
// läd die excel datei
string[] excelFiles = this.GetExcelFiles();
ExcelLoader eloader = new ExcelLoader();
var task = eloader.StartLoading(excelFiles);
return task.ContinueWith(t =>
{
foreach (DataSet elem in eloader.Tables)
{
this.ActivateItem(new ExcelViewModel(elem) { DisplayName = elem.DataSetName });
}
});
}
你的惊人方法似乎缺少任何等待陈述。async关键字不会神奇地使方法能够异步运行。您可以等待Task.Delay作为Thread.Sleep的异步替代品。对于非常长的操作,如果是CPU受限的,可能需要生成一个新线程。如果它是IO绑定的,那么问题在于您是否有权访问可以使用的异步API
请参阅MSDN第9频道,以了解良好介绍的开始。您的惊人加载方法似乎缺少任何等待声明。async关键字不会神奇地使方法能够异步运行。您可以等待Task.Delay作为Thread.Sleep的异步替代品。对于非常长的操作,如果是CPU受限的,可能需要生成一个新线程。如果它是IO绑定的,那么问题在于您是否有权访问可以使用的异步API
请参阅MSDN第9频道,了解一个好的介绍的开始。我怀疑问题可能是等待eloader.StartingExcelFiles的行;实际上正在同一UI线程上运行。您需要像下面这样执行它。这将导致该方法在线程池线程上运行
await Task.Run(eloader.StartLoading(excelFiles));
我怀疑问题可能是该行正在等待eloader.startingExcelFiles;实际上正在同一UI线程上运行。您需要像下面这样执行它。这将导致该方法在线程池线程上运行
await Task.Run(eloader.StartLoading(excelFiles));
用wait Task.Delay5000代替它。我想,请仔细阅读一下异步,而不仅仅是实验。我有,包括,都很好,现在有几本书也涵盖了它。@Stephen Cleary:事实上,我之前读过你的博客文章-不幸的是,我没有抓住线程部分。附带说明:在尝试从您的博客文章中获取TAP文档时,出现了一个错误。也许链接已经过时了?我在一两个月前更改了链接。我想,请仔细阅读一下异步,而不仅仅是实验。我有,包括,都很好,现在有几本书也涵盖了它。@Stephen Cleary:事实上,我之前读过你的博客文章-不幸的是,我没有抓住线程部分。附带说明:在尝试从您的博客文章中获取TAP文档时,出现了一个错误。也许链接已经过时了?我在一两个月前更改了链接。只是仔细检查了一下,它现在正在工作…@Erik Schierboom你们两个方法都导致了一个错误,返回语句后不允许使用object语句。我使用的是德语版本,所以这是一个粗略的翻译。你在返回语句后做了什么吗?还是按原样实现了代码段?在很长的操作部分有几个过程调用,包括try..catch。epplus包在using块中使用。如果您只是按原样包含代码段,它不会给您错误。请尝试一下,如果错误消失了,那么请在很长的操作中发布代码-part@ChristianSauer很抱歉,我的代码有一个错误。我刚刚更新了我的答案。@Erik Schierboom你们两个方法在返回语句之后都导致了一个错误。不允许使用对象语句。我使用的是德语版本,所以这是一个粗略的翻译。你们在返回语句之后做什么了吗?还是按原样实现了代码段?在很长的操作部分有几个过程调用,包括try..catch。epplus包在using块中使用。如果您只是按原样包含代码段,它不会给您错误。请尝试一下,如果错误消失了,那么请在很长的操作中发布代码-part@ChristianSauer很抱歉,我的代码有一个错误。我刚刚更新了我的答案。谢谢你的解释和链接。事实上,这个程序可能是两者兼而有之:它读取数据并动态转换它们。谢谢你的解释和链接。行为
事实上,这个程序可能是两者兼而有之:它可以动态读取数据并进行转换。感谢您的帮助!我会用ContinueWith方法查找,我不知道它做什么@ChristianSauer ContinueWith方法的基本功能是允许将代码附加到方法完成时调用的任务。谢谢你的帮助!我会用ContinueWith方法查找,我不知道它做什么@ChristianSauer ContinueWith方法的基本功能是允许将代码附加到方法完成时调用的任务。我假定您不想在惊人的加载完成之前运行“foreach DataSet elem in eloader.Tables”语句。等待惊人加载将导致执行返回到最初调用CmdLoadExcel的方法,并仅在惊人加载完成后执行foreach。我猜想您不希望在惊人加载完成之前运行“foreach DataSet elem in eloader.Tables”语句。等待StartLoading将导致执行返回到最初调用CmdLoadExcel的方法,并仅在StartLoading完成后执行foreach。