问题
What prevents me from constantly using the async/wait pattern in my .net code is that once you create an async method the async keyword tends to spread thru my code forcing me to make all methods async. Is there a pattern to stop this efficiently?
回答1:
What prevents me from constantly using the async/wait pattern in my .net code is that once you create an async method the async keyword tends to spread thru my code forcing me to make all methods async. Is there a pattern to stop this efficiently?
Let me ask you this, then: why are you using async
/await
? You need to take a step back and decide if you want the benefits of asynchronous code. If you do want those benefits, then your code must be asynchronous. As soon as you block a thread, you lose all the benefits of async. So really, why use asynchronous code at all, if you're just going to block a thread anyway?
That said, there are some scenarios where a partially-async
stack makes sense. For example, if your code base is temporarily in a transition state. In this case, you can use one of the hacks described in my article on brownfield async:
- Blocking directly (may cause deadlocks).
- Blocking on a thread pool thread (executes code on a different thread and different context, may cause unexpected parallelism).
- Blocking on the current thread with a thread pool context (executes code in a different context, may cause unexpected parallelism).
- Blocking on a thread with a single-threaded context (executes code on a different thread and different context).
- Blocking on a nested message loop (may cause unexpected reentrancy).
All of these are hacks, and all have different drawbacks. There is no hack that works in every scenario.
回答2:
As commented earlier you should go async all the way...
In some cases we use a litle helper class to cut off the async pattern. This class alows you to wait for the result without ending up with a deadlock by replacing the SynchronizationContext.
public class NoSynchronizationContextScope : IDisposable
{
private readonly SynchronizationContext synchronizationContext;
public NoSynchronizationContextScope()
{
synchronizationContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
}
public void Dispose() => SynchronizationContext.SetSynchronizationContext(synchronizationContext);
}
void fn()
{
using (new NoSynchronizationContextScope())
{
fnAsync().Wait();
// or
// var result = fnAsync().Result();
// in case you have to wait for a result
}
}
回答3:
You can use async method and invoke not async method in task so outer method will behave like async and inner method is still sync.
public async Task OuterFuncAsync()
{
await Task.Run(() => InnerFunc());
}
回答4:
In the very particular case of a method that you want to start running but not wait for the result of (i.e. triggering an event handler) you can use async void. Just make sure you catch all the errors at that point:
public async void DoSomething() {
try {
var o = await DoThing1();
await DoThing2(o);
} catch (Exception e) {
// Log the error somewhere (to a file, database, etc.)
}
}
来源:https://stackoverflow.com/questions/44270633/avoid-async-from-spreading-in-method-signatures