c# - 在 C# 中执行异步操作的正确方法
问题描述
我有一个类需要很长时间才能启动,因为它在构造函数中执行了一些长时间运行的操作。我需要创建 3 个这样的对象并将它们添加到字典中。
我正在尝试使用 async 来创建 3 个线程,每个线程都启动这些对象中的一个,但发现它有点令人困惑。
最初我以为我会等到所有线程都完成,然后将结果添加到字典中,但是我无法编译代码,所以我求助于做字典。在线程中添加(这是好的?)
我写了以下代码
public void CreateAccountStuffs(ICollection<Account> accounts)
{
CreateStuff(accounts);
}
private async void CreateStuff(ICollection<Account> accounts)
{
var tasks = accounts.Select(a => CreateStuffForAccount(a));
await Task.WhenAll(tasks);
}
private Task CreateStuffForAccount(Account account)
{
//Long Running process due to website calls in AccountWrapper construction
var accountWrapper = new AccountWrapper(account);
return Task.FromResult(accountWrapper);
}
最后一行似乎毫无意义,但没有它我无法编译代码。我觉得我在这里遗漏了一些非常明显的东西,但是我的多线程技能太生疏了,我很难看到什么。
我的直觉是,有一种更简单的方法来编写我需要做的事情,但我不知道那是什么。
例如,我注意到这个问题似乎表明您可以编写一个返回 Task 的方法,并简单地在方法主体中编写返回“This String”,但是,该构造不会为我编译。我收到错误无法从字符串转换为任务
注意 - 编辑删除不属于问题的代码 - 之前涉及 2 个构造函数,这使事情变得混乱 - 这是 AccountWrapper 中的构造函数长期运行。
解决方案
将异步方法放在构造函数中而不等待它不是一个好的设计。因为当你的代码从构造函数返回时,如果构造已经完成并且你的类实例可能处于不一致的状态,你现在不会这样做。您可以简单地创建静态工厂方法
public class MyClass
{
private readonly IDictionary<int, IAccountStuff> _accountStuffs;
private readonly ICollection<Account> _accounts;
protected MyClass()
{
_accounts = dataLayer.GetAccounts();
// remove it
// CreateStuff(accounts);
}
private async void CreateStuff(ICollection<Account> accounts)
{
var tasks = accounts.Select(a => CreateStuffForAccount(a));
await Task.WhenAll(tasks);
}
private Task CreateStuffForAccount(Account account)
{
//Long Running process due to website calls in AccountWrapper construction
return Task.Run(async () =>
{
// do something with you account
// to do this you dictionary should be concurrent
this._accountStuffs.Add(account.Id, accountWrapper.Stuff);
});
}
// factory method
public static async Task Create()
{
var myClass = new MyClass();
await myClass.CreateStuff();
}
}
....
// and somwhere you may use
public async Task Foo()
{
var myClass = await MyClass.Create();
// now you can safely use you class instance myClass
}
推荐阅读
- .net-core - 如何在 AZURE 应用程序网关上启用 CORS
- reactjs - 基于功能的组件标记问题
- mysql - 如何在同一个表中更新具有外键约束的列
- node.js - 如何解决以数组为输入的 GraphQl 突变
- java - 错误 - com.google.firebase.database.DatabaseException:无法将 java.lang.String 类型的对象转换为 com.example.project_sewing.Event1 类型
- r - 展开 data.frame/table
- php - 为什么 Hash::check 总是返回 false?
- google-bigquery - 如何在不同值小于 Google BigQuery 中的给定数字的情况下对每列进行数组聚合?
- r - 在R中按日期将文件复制到目录中
- raspberry-pi - Bluez 与我的 BLE 遥控器配对后崩溃