【问题标题】:Advice on two implementations of async/await关于 async/await 的两种实现的建议
【发布时间】:2015-04-08 13:13:50
【问题描述】:

我注意到我可以通过以下两种方式获取数据(参考选项 1 和选项 2),并且想知道选择其中一种方式是否有任何影响/好处?我正在使用 .NET 4.5.1,并且正在使用 async/await 从本地 SQL Server 加载数据。

// ***** OPTION 1 *****

// Constructor
public SomeViewModel(IProjectService projectService)
{
    Task.Run(async () => await GetAllDataAsync());
}

// This method calls out all of the other local async/await methods to download the data
private async Task GetAllDataAsync()
{
    await GetProjectDataAsync();
    await GetAssignmentDataAsync();
    ... more await calls ...
}  

// A typical method call to get data from service
private async Task GetProjectDataAsync()
{
    var projects = await projectService.GetProjectsAsync();
    this.ProjectList = projects;
}

// ***** OPTION 2 *****

// Constructor
// I call Task.Run() for all of the methods that download data
public SomeViewModel()
{
    _service = service;
    Task.Run(async () => await this.GetProjectDataAsync());
    Task.Run(async () => await this.GetAssignmentDataAsync());
    ... more Task.Run() calls ...
} 

// A typical method call to get data from service
private async Task GetProjectDataAsync()
{
    var projects = await projectService.GetProjectsAsync();
    this.ProjectList = projects;
}

编辑 1:

这是我的存储库中的 async/await 方法的示例:

public async Task<IList<Project>> GetProjectsAsync()
{
    using (Context ctx= new ProjectContext())
    {
        IEnumerable<Project> myProjects = ctx.Projects;
        return await myProjects.ToListAsync();
    }
}

编辑 2: 我目前通过Stephen Cleary 购买了这本书Concurrency in C# Cookbook,并正在结合此处给出的建议从书中寻找合适的解决方案。谁能指出本书的某些部分可以在我的场景中为我提供帮助,即从许多表中加载大量数据以供应用程序使用?

编辑 3:

// ***** 选项 3 *****

// Constructor
public SomeViewModel()
{
    _service = service;
    DownloadData();
} 

// A normal method that awaits async methods
private void DownloadData()
{
    Task.Run(async () => await GetProjectDataAsync());
    Task.Run(async () => await GetAssignmentDataAsync());
    ... more await calls to async Task methods that call services that in turn have async Task methods
}

【问题讨论】:

  • 为什么所有的Task.Run 电话?如果异步方法是真正异步的,为什么需要在单独的任务中运行它们?您可能要考虑的一件事是拥有一个静态异步工厂方法,该方法首先获取所有数据,然后调用一个准备好所有数据的构造函数。这样你就可以获得不可变类型和异步的好处,这通常与构造函数不能异步的事实不符。
  • (1) 是顺序的,(2) 是并行的;哪个可能更好地工作取决于底层方法正在做什么,但是如果它们正在访问共享数据库,例如,它们可能最终会争夺共享资源,从而降低并行运行它们的好处甚至由于任务切换的开销增加而使性能变差。
  • @JonSkeet - 我目前正在研究这些替代方案,并会报告,谢谢!
  • @DanBryant - 我确实认为选项 2 是更好的选择。我目前正在查看建议,谢谢!

标签: c# asynchronous async-await task


【解决方案1】:

我怀疑其中任何一个都适合您的需求。由于构造函数不能是async,因此没有办法等到您开始的任务完成。你可以打电话给Task.Wait,但这会抵消异步带来的所有好处,你需要处理由此产生的死锁。

现在,您启动的任务与其余的请求处理同时运行。这可能是活泼的,而不是你想要的。如果这曾经奏效,那是偶然的。

将该代码从 ctor 移出到一个普通方法中,并一直使用 await

【讨论】:

  • 我添加了一个选项 3。根据您的评论,“一直等待”,我的新代码是否符合此要求,或者您有什么想法,谢谢。
  • 您刚刚尝试使用选项 3 作弊。将这些东西移到新方法中不会改变任何事情。 DownloadData 返回 void,因此调用者不能等待它。这意味着比赛仍然存在。这也告诉我你不明白 await 是如何工作的。你应该研究它,因为以你目前的理解水平,你是在玩火。
  • 您最初说“将代码从 ctor 移到普通方法中......”我相信 void DownloadData() 是不是?其他部分可能是错误的,但这本身就是一种“普通方法”。此外,您提到的选项 3 是错误的,但经过一些测试,这些任务在不同的核心上运行。这实际上是我从别人那里抢来的。
  • 好的。您需要等待最终生成的所有任务。 Async void 是不可取的,因为这相当于将异步方法的任务扔掉。因此,请安排代码,以便没有 async void 并且最终等待一切。这意味着在构造函数调用下方的调用树的一部分中不能有等待。这样做:var x = new MyObj(); await x.Init();。类似的东西。
猜你喜欢
  • 1970-01-01
  • 2019-09-22
  • 2021-06-01
  • 2012-05-16
  • 2012-06-15
  • 1970-01-01
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多