【问题标题】:Correct use of Async/Await [closed]正确使用 Async/Await [关闭]
【发布时间】:2014-08-12 22:40:48
【问题描述】:

这是我的 async/await 实现,但我不确定我是否正确执行。

代码按预期工作,但我希望有人检查这段小代码以指出任何错误。

public class DbUtils
{

    public static List<string> GetDataSources()
    {
        //I have removed some logic from here as it's not important to my question
        List<string> names = new List<string>();
        names = SomeClass.SomeLongSystemMethod();
        return names;
    }

    public static async Task<List<string>> GetDataSourcesAsync()
    {
        //This is a place where I have my doubts
        return await Task.Run(() =>
        {
            return GetDataSources();
        });
    }
}

public class SomeOtherClass
{
    private async void BT_RefreshServerName_Click(object sender, EventArgs e)
    {
        CB_ServerName.DataSource = await DbUtils.GetDataSourcesAsync();
    }
}

编辑:

我的新版本代码如下所示。

public class SomeOtherClass
{
    private async void BT_RefreshServerName_Click(object sender, EventArgs e)
        {
            try
            {
                BT_RefreshServerName.Enabled = false;

                //.ConfigureAwait(true) (this is a default) is to attempt to
                //marshal the continuation back to the original context as the
                //result is used to update UI.                    
                CB_ServerName.DataSource = await Task.Run(
                 () => DbUtils.GetDataSources()).ConfigureAwait(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK);
            }
            finally
            {
                BT_RefreshServerName.Enabled = true;
            }
        }
    }
}

public class DbUtils
{

    public static List<string> GetDataSources()
    {
        //Some logic

        List<string> names = new List<string>();
        names = SomeClass.SomeLongSystemMethod();
        return names;
    }
}

【问题讨论】:

  • 这个问题似乎跑题了,因为它属于codereview.stackexchange.com
  • @RemusRusanu 我不知道有一个单独的部分。谢谢你告诉我这件事。下次我将使用 codereview 部分。
  • 如果您在等待任务后不做任何事情,您可以简单地返回任务。这将有助于优化您的代码,因为它不需要创建代理任务。所以GetDataSourcesAsync可以改成return Task.FromResult(GetDataSources());然后去掉函数上的async修饰符
  • @JLevett 谢谢!这正是我正在寻找的答案。干杯

标签: c# async-await .net-4.5


【解决方案1】:

GetDataSourcesAsync 的实现被称为“异步优于同步”,并且通常被认为是一种反模式(尽管公平地说,它并不像“同步优于异步”那么糟糕)。至少它会起作用,但如果你实际上没有真正的async 操作,那么使用工作线程(通常是线程池)和Invoke 并没有什么区别/BeginInvoke 取回 UI 线程(进行 UI 更新)。

如果这是问题,它会起作用。

现在,如果GetDataSourcesAsync 实际使用了*Async 数据访问方法; 然后这将是很棒的代码。在那种情况下,你不需要Task.Run,顺便说一句。

另外:为您的事件处理程序添加一些异常处理。

【讨论】:

  • 我知道我可以使用线程池。我试图摆脱在使用 .NET 3.5 时用来处理 UI 操作的额外代码。正如您所建议的那样,我将放弃使用这种反模式。您能否查看我在问题中的编辑并查看新版本?我试图在这个问题中使用尽可能少的代码,所以这里没有异常处理;)
  • @Rafał.S 我真的不确定编辑是否与我的建议一致......我的建议是不要使用“异步超过同步”,你仍在这样做。我的建议也是使用异步数据访问 API,您没有这样做。
  • 在更多地阅读(this 和其他文章)关于这个主题之后,我明白为什么我错过了你的观点。但是,我仍然对“(..)使用异步数据访问 API 感到困惑,而您没有这样做。”在这个情况下。我将“异步数据访问 API”理解为 .Wait()/ConfigureAwait() 等方法,但我认为我只是对这个话题感到不知所措,因为我今天才切换到 .NET 4.5。我在编辑中更改了代码以匹配我当前的实现,该实现按预期工作,我认为现在是更好的代码。
  • @Rafał.S 不,.Wait() 和 .ConfigureAwait() 本身并不是异步的;有简单的延续 API。要完全异步,最好将异步 API 向下使用到底部 - 例如,SqlCommand.ExecuteNonQueryAsync / SqlCommand.ExecuteReaderAsync 等
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 2020-08-23
  • 2022-01-07
  • 2013-08-14
相关资源
最近更新 更多