异步等待 - 避免阻止UI是正确的想法吗?

时间:2013-04-15 13:01:54

标签: c# asynchronous

我认为使用await / async是确保响应式UI的最佳方法。但我似乎做错了什么,因为无论如何我的申请都冻结了。

我尝试做的事: 按钮已启动,应等待持续运行。

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

它只是在睡眠时停止,我不确定我做错了什么。

4 个答案:

答案 0 :(得分:3)

使用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

答案 1 :(得分:2)

Yor StartLoading方法似乎缺少任何await语句。 async关键字不会神奇地使方法能够异步运行。您可以await Task.Delay作为Thread.Sleep的异步替换。对于您的长时间操作,如果它受CPU限制,您可能需要生成一个新线程。如果它是IO绑定的,那么您是否可以访问可以使用的Async API是一个问题。

有关良好介绍的开始,请参阅MSDN第9频道上的Three Essential Tips For Asysnc

答案 2 :(得分:1)

问题是您的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 });
                }
            });
 }

答案 3 :(得分:1)

我怀疑问题可能是“await eloader.StartLoading(excelFiles);”实际上是在同一个(UI)线程上运行。你需要像下面这样执行它。这将导致该方法在ThreadPool线程上运行。

await Task.Run(eloader.StartLoading(excelFiles));