Preface
First of all, immediately explain why there is such a pseudo-titled Demo essay? It’s not that I have a misunderstanding of knowledge or want to mislead others because everyone knows that emit writes are synchronous methods, it is impossible to await, at least it has not provided corresponding functions for so many years.
Begin with Demo
The original method is a method that returns 55 after a delay of 2 seconds:
public static async Task<int> GetV()
{
await Task.Delay(2000);
return 55;
}
Now we need to add 6 to the result of 55 so that the final result becomes 61.
Our test method is like this, it will output some simple time to help us understand the execution order and asynchronous situation.
private static async Task Test(MethodInfo method, MethodInfo awaitMehtod)
{
var caller = CreateCaller(method, awaitMehtod);
Console.WriteLine($"Start {awaitMehtod.Name} at: {DateTime.Now}.");
var task = caller();
Console.WriteLine($"Call done at: {DateTime.Now}.");
var number = await task;
Console.WriteLine($"Hello {number} at: {DateTime.Now}.");
Console.WriteLine($"End at: {DateTime.Now}.");
Console.WriteLine();
}
1. ContinueWith
public static Func<Task<int>> CreateCaller(MethodInfo method, MethodInfo awaitMehtod)
{
var m = new DynamicMethod(Guid.NewGuid().ToString("N"),
typeof(Task<int>), Type.EmptyTypes);
var il = m.GetILGenerator();
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Call, typeof(Program).GetMethod
(nameof(Program.AddSixUseContinueWith)));
il.Emit(OpCodes.Ret);
return m.CreateDelegate(typeof(Func<Task<int>>)) as Func<Task<int>>;
}
public static Task<int> AddSixUseContinueWith(Task<int> task)
{
return task.ContinueWith(i =>
{
Console.WriteLine($"AddSixUseContinueWith is: {DateTime.Now}.");
return i.Result + 6;
});
}
Test Results
Start AddSixUseContinueWith at: 2021/1/2 13:34:55.
Call done at: 2021/1/2 13:34:55.
AddSixUseContinueWith is: 2021/1/2 13:34:57.
Hello 61 at: 2021/1/2 13:34:57.
End at: 2021/1/2 13:34:57.
Advantage
Still really asynchronous
Disadvantage
The cost is relatively large. After all, there is no optimization such as the state machine. (The cost is at the ns level, not the ms you think.)
2. GetAwaiter().GetResult()
public static Func<Task<int>> CreateCaller(MethodInfo method, MethodInfo awaitMehtod)
{
var m = new DynamicMethod(Guid.NewGuid().ToString("N"),
typeof(Task<int>), Type.EmptyTypes);
var il = m.GetILGenerator();
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Call, typeof(Program).GetMethod
(nameof(Program.AddSixUseAwaiter)));
il.Emit(OpCodes.Ret);
return m.CreateDelegate(typeof(Func<Task<int>>)) as Func<Task<int>>;
}
public static Task<int> AddSixUseAwaiter(Task<int> task)
{
var r = task.ConfigureAwait(false).GetAwaiter().GetResult() + 6;
Console.WriteLine($"AddSixUseAwaiter is: {DateTime.Now}.");
return Task.FromResult(r);
}
Test Results
Start AddSixUseAwaiter at: 2021/1/2 13:34:57.
AddSixUseAwaiter is: 2021/1/2 13:34:59.
Call done at: 2021/1/2 13:34:59.
Hello 61 at: 2021/1/2 13:34:59.
End at: 2021/1/2 13:34:59.
Advantage
Very small execution time
Disadvantage
Of course, in this way, asynchronous has become synchronous, so in some cases, we may operate improper code and lose the advantages of asynchronous methods.
3. async/await
public static Func<Task<int>> CreateCaller(MethodInfo method, MethodInfo awaitMehtod)
{
var m = new DynamicMethod(Guid.NewGuid().ToString("N"),
typeof(Task<int>), Type.EmptyTypes);
var il = m.GetILGenerator();
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Call, typeof(Program).GetMethod
(nameof(Program.AddSixUseAsyncAwait)));
il.Emit(OpCodes.Ret);
return m.CreateDelegate(typeof(Func<Task<int>>)) as Func<Task<int>>;
}
public static async Task<int> AddSixUseAsyncAwait(Task<int> task)
{
var r = await task;
Console.WriteLine($"AddSixUseAsyncAwait is: {DateTime.Now}.");
return r + 6;
}
Test Results
Start AddSixUseAsyncAwait at: 2021/1/2 13:34:59.
Call done at: 2021/1/2 13:34:59.
AddSixUseAsyncAwait is: 2021/1/2 13:35:01.
Hello 61 at: 2021/1/2 13:35:01.
End at: 2021/1/2 13:35:01.
Advantage
The advantages of async / await are not lost.
Disadvantage
I originally wanted to migrate the result processing logic in emit to the async
/ await
method, and the emit code must be well designed.
All of the Demo On
https://github.com/fs7744/grocery/blob/main/csharp/emit_await/EmitAwaitDemo/Program.cs
Sharing is not easy, if you can give a little motivation, I would be very grateful: pay attention to my open source project:Norns.Urd
History
- 2nd January, 2021: Initial version
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.