Vla*_*lad 17 c# multithreading asynchronous async-await
假设我有一个实现的接口方法
public void DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
}
Run Code Online (Sandbox Code Playgroud)
过了一段时间,我意识到我想改变它:
public async Task DoSomething(User user)
{
if (user.Gold > 1000) ChatManager.Send(user, "You are rich: " + user.Gold);
if (!user.HasReward)
{
using(var dbConnection = await DbPool.OpenConnectionAsync())
{
await dbConnection.Update(user, u =>
{
u.HasReward = true;
u.Gold += 1000;
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在更改界面中的方法签名.但调用方法是同步的,我不仅要使它们异步,还要使整个调用树异步.
例:
void A()
{
_peer.SendResponse("Ping: " + _x.B());
}
double X.B()
{
return _someCollection.Where(item => y.C(item)).Average();
}
bool Y.C(int item)
{
// ...
_z.DoSomething();
return _state.IsCorrect;
}
Run Code Online (Sandbox Code Playgroud)
应改为
async void AAsync()
{
_peer.SendResponse("Ping: " + await _x.BAsync());
}
async Task<double> X.BAsync()
{
// await thing breaks LINQ!
var els = new List<int>();
foreach (var el in _someCollection)
{
if (await y.CAsync(item)) els.Add(el);
}
return _els.Average();
}
async Task<bool> Y.CAsync(int item)
{
// ...
await _z.DoSomething();
return _state.IsCorrect;
}
Run Code Online (Sandbox Code Playgroud)
受影响的调用树可能非常大(许多系统和接口),因此很难做到这一点.
当A从接口方法调用第一个方法时IDisposable.Dispose- 我无法使其异步.
另一个例子:假设多个调用A被存储为委托.以前他们只是叫用_combinedDelegate.Invoke(),但现在我应该去通过GetInvocationList(),并await在每个项目上.
哦,并考虑用异步方法替换属性getter.
我不能使用Task.Wait()或.Result因为:
ThreadPool在服务器应用程序中浪费线程ThreadPool线程Wait都没有线程来完成任何任务.所以问题是:async即使我不打算在内部调用任何异步,我是否应该最初完全使用我的所有方法?它会不会影响性能?或者如何设计东西以避免这种难以重构?
Ste*_*ary 18
即使我不打算在内部调用任何异步,我是否应该首先使我的所有方法完全异步?
这个设计问题与问题async基本相同IDisposable.也就是说,接口必须预测它们的实现.不管你做什么,这都会很混乱.
根据我的经验,考虑一个方法/接口/类并预测它是否会使用I/O通常是相当简单的.如果它需要I/O,那么它可能应该返回任务.有时(但不总是),可以构建代码,以便I/O在代码的自己的部分完成,使业务对象和逻辑严格同步.JavaScript世界中的Redux模式就是一个很好的例子.
但最重要的是,有时你会做出错误的调用并且必须重构.我认为这比使每个方法异步更好.你是否使每个接口继承IDisposable并using在任何地方使用?不,你只在必要时添加它; 你应该采取相同的方法async.