Fire and forget Task
概念¶
-
async void的方法是无法被await的,由于没有await关键字标记,因此其后的逻辑并不会被编译器组织为异步回调。 -
调用
async void方法的方法在调用完async void后返回继续执行,async void会在线程池线程上执行。
假设要在执行完这个异步任务后需要关闭进度条,由于
async void无法被await修饰,进度条会直接被设置为结束,看上去像是没有显示一样。
一些用例¶
using System.Diagnostics;
namespace Tests.CSharp;
[TestClass]
public class FireAndForgetTaskTest
{
private const int DELAY_MILLISECONDS = 3000;
[TestMethod]
public async Task FireAndForgetTaskReturnsImmediately()
{
Stopwatch stopwatch = new();
stopwatch.Restart();
FireAndForgetMethod();
stopwatch.Stop();
// time comsuming of just a method call
Assert.IsLessThan(100, stopwatch.ElapsedMilliseconds);
}
/// <summary>
/// Actually when we say 'return', it is something like Task.Continuation callback.
/// </summary>
/// <returns></returns>
[TestMethod]
public async Task AwaitableTaskReturnsAfterRunning()
{
Stopwatch stopwatch = new();
stopwatch.Restart();
await AwaitableMethod();
stopwatch.Stop();
Assert.IsGreaterThan(DELAY_MILLISECONDS, stopwatch.ElapsedMilliseconds);
}
[TestMethod]
public async Task AsyncActionIsFireAndForget()
{
Action action = async () => { await Task.Delay(DELAY_MILLISECONDS); };
// Equals:
//static async void action() { await Task.Delay(MILLISECONDS); }
Stopwatch stopwatch = new();
stopwatch.Restart();
// cannot await void
action.Invoke();
stopwatch.Stop();
Assert.IsLessThan(100, stopwatch.ElapsedMilliseconds);
}
[TestMethod]
public async Task FireAndForgetMethodIsNotAwaitableEventItsInTaskRun()
{
static async void action() { await Task.Delay(DELAY_MILLISECONDS); }
Stopwatch stopwatch = new();
stopwatch.Restart();
await Task.Run(action);
stopwatch.Stop();
Assert.IsLessThan(100, stopwatch.ElapsedMilliseconds);
}
[TestMethod]
public async Task CallAsyncMethodWithoutAwaitMakesItFireAndForget()
{
Stopwatch stopwatch = new();
stopwatch.Restart();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
AwaitableMethod();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
stopwatch.Stop();
Assert.IsLessThan(100, stopwatch.ElapsedMilliseconds);
}
[TestMethod]
public async Task AwaitableMethodIsAwaitableEventItsInTaskRun()
{
static async Task action() { await Task.Delay(DELAY_MILLISECONDS); }
Stopwatch stopwatch = new();
stopwatch.Restart();
await Task.Run(action);
stopwatch.Stop();
Assert.IsGreaterThan(DELAY_MILLISECONDS, stopwatch.ElapsedMilliseconds);
}
/// <summary>
/// Cannot await void
/// </summary>
private static async void FireAndForgetMethod()
{
await Task.Delay(DELAY_MILLISECONDS);
}
private static async Task AwaitableMethod()
{
await Task.Delay(DELAY_MILLISECONDS);
}
}