Within an async
method, any local variables are stored away so that when whatever thread continues after the await
will have access to the values. Is there any way to indicate which values are really needed after the await
?
For example:
var firstName = "Karl";
var lastName = "Anderson";
var street1 = "123 Nowhere Street";
var street2 = "Apt 1-A";
var city = "Beverly Hills";
var state = "California";
var zip = "90210";
await MyTaskHere();
Console.WriteLine(firstName);
Console.WriteLine(city);
So I have declared 7 local variables, but only use 2 of them after the await
, is there any attribute I can decorate my variables with to indicate that I intend to only use firstName
and city
after the await
completes?
Note: This is a contrived example, but it seems like it might be beneficial to be able to curb the storage of potentially large data chunks if they are not needed when the next thread comes to finish the work.
No problem, just make a loop and call this function with an await: [code] for (int i = pendingList. Count - 1; i >= 0; i--)
The main benefits of asynchronous programming using async / await include the following: Increase the performance and responsiveness of your application, particularly when you have long-running operations that do not require to block the execution.
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.
An async keyword is a method that performs asynchronous tasks such as fetching data from a database, reading a file, etc, they can be marked as “async”. Whereas await keyword making “await” to a statement means suspending the execution of the async method it is residing in until the asynchronous task completes.
No, you cannot. (Other than the obvious solutions of splitting them up into separate methods or setting them to null
).
The compiler is not fully optimized in this scenario; it may capture more variables than it needs and may hold onto them longer than necessary. This is probably something Microsoft will optimize in the future.
You can run Ildasm.exe
on your program to see what code the compiler generates. I've tried to do this but unfortunately my IL skills are a bit lacking, however you can see that all the local variables are captured as fields of the generated <Foo>d__0
class. Given this program:
using System;
using System.Threading.Tasks;
namespace AsyncCaptureVariables
{
class Program
{
public async Task Foo()
{
var firstName = "Karl";
var lastName = "Anderson";
var street1 = "123 Nowhere Street";
var street2 = "Apt 1-A";
var city = "Beverly Hills";
var state = "California";
var zip = "90210";
await Task.Delay(5000);
Console.WriteLine(firstName);
Console.WriteLine(city);
}
public static void Main()
{
var program = new Program();
Task t = program.Foo();
t.Wait();
}
}
}
The compiler generates something like the following partially converted to C# code:
using System;
class Program : System.Object
{
class <Foo>d__0 : System.ValueType, System.Runtime.CompilerServices.IAsyncStateMachine
{
public int32 <>1__state;
public System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>t__builder;
public class AsyncCaptureVariables.Program <>4__this;
public string <firstName>5__1;
public string <lastName>5__2;
public string <street1>5__3;
public string <street2>5__4;
public string <city>5__5;
public string <state>5__6;
public string <zip>5__7;
private System.Runtime.CompilerServices.TaskAwaiter <>u__$awaiter8;
private object <>t__stack;
void MoveNext()
{
try
{
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: ldfld int32 AsyncCaptureVariables.Program/'<Foo>d__0'::'<>1__state'
IL_0008: stloc.2
IL_0009: ldloc.2
IL_000a: ldc.i4.s -3
IL_000c: beq.s IL_0014
IL_000e: ldloc.2
IL_000f: ldc.i4.0
IL_0010: beq.s IL_0019
IL_0012: br.s IL_001e
IL_0014: br IL_00ee
IL_0019: br IL_00a8
IL_001e: br.s IL_0020
//000009: {
IL_0020: nop
//000010: var firstName = "Karl";
IL_0021: ldarg.0
IL_0022: ldstr "Karl"
IL_0027: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<firstName>5__1'
//000011: var lastName = "Anderson";
IL_002c: ldarg.0
IL_002d: ldstr "Anderson"
IL_0032: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<lastName>5__2'
//000012: var street1 = "123 Nowhere Street";
IL_0037: ldarg.0
IL_0038: ldstr "123 Nowhere Street"
IL_003d: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<street1>5__3'
//000013: var street2 = "Apt 1-A";
IL_0042: ldarg.0
IL_0043: ldstr "Apt 1-A"
IL_0048: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<street2>5__4'
//000014: var city = "Beverly Hills";
IL_004d: ldarg.0
IL_004e: ldstr "Beverly Hills"
IL_0053: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<city>5__5'
//000015: var state = "California";
IL_0058: ldarg.0
IL_0059: ldstr "California"
IL_005e: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<state>5__6'
//000016: var zip = "90210";
IL_0063: ldarg.0
IL_0064: ldstr "90210"
IL_0069: stfld string AsyncCaptureVariables.Program/'<Foo>d__0'::'<zip>5__7'
//000017:
//000018: await Task.Delay(5000);
IL_006e: ldc.i4 0x1388
IL_0073: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Delay(int32)
IL_0078: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter()
IL_007d: stloc.3
IL_0078: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter()
IL_007d: stloc.3
IL_007e: ldloca.s CS$0$0001
IL_0080: call instance bool [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::get_IsCompleted()
IL_0085: brtrue.s IL_00c6
IL_0087: ldarg.0
IL_0088: ldc.i4.0
IL_0089: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_008e: ldarg.0
IL_008f: ldloc.3
IL_0090: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_0095: ldarg.0
IL_0096: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_009b: ldloca.s CS$0$0001
IL_009d: ldarg.0
IL_009e: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter,valuetype AsyncCaptureVariables.Program/<Foo>d__0>(!!0&,
!!1&)
IL_00a3: nop
IL_00a4: ldc.i4.0
IL_00a5: stloc.0
IL_00a6: leave.s IL_011d
IL_00a8: ldarg.0
IL_00a9: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_00ae: stloc.3
IL_00af: ldarg.0
IL_00b0: ldloca.s CS$0$0002
IL_00b2: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter
IL_00b8: ldloc.s CS$0$0002
IL_00ba: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter AsyncCaptureVariables.Program/<Foo>d__0::<>u__$awaiter8
IL_00bf: ldarg.0
IL_00c0: ldc.i4.m1
IL_00c1: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_00c6: ldloca.s CS$0$0001
IL_00c8: call instance void [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::GetResult()
IL_00cd: nop
IL_00ce: ldloca.s CS$0$0001
IL_00d0: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter
//000019:
//000020: Console.WriteLine(firstName);
IL_00d6: ldarg.0
IL_00d7: ldfld string AsyncCaptureVariables.Program/<Foo>d__0::<firstName>5__1
IL_00dc: call void [mscorlib]System.Console::WriteLine(string)
IL_00e1: nop
//000021: Console.WriteLine(city);
IL_00e2: ldarg.0
IL_00e3: ldfld string AsyncCaptureVariables.Program/<Foo>d__0::<city>5__5
IL_00e8: call void [mscorlib]System.Console::WriteLine(string)
IL_00ed: nop
//000022: }
//000023:
//000024: public static void Main()
//000025: {
//000026: var program = new Program();
//000027: Task t = program.Foo();
//000028: t.Wait();
//000029: }
//000030: }
//000031: }
IL_00ee: leave.s IL_0108
} // end .try
catch [mscorlib]System.Exception
{
IL_00f0: stloc.1
IL_00f1: ldarg.0
IL_00f2: ldc.i4.s -2
IL_00f4: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
IL_00f9: ldarg.0
IL_00fa: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_00ff: ldloc.1
IL_0100: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetException(class [mscorlib]System.Exception)
IL_0105: nop
IL_0106: leave.s IL_011d
} // end handler
IL_0108: nop
//000022: }
IL_0109: ldarg.0
IL_010a: ldc.i4.s -2
IL_010c: stfld int32 AsyncCaptureVariables.Program/<Foo>d__0::<>1__state
//000023:
//000024: public static void Main()
//000025: {
//000026: var program = new Program();
//000027: Task t = program.Foo();
//000028: t.Wait();
//000029: }
//000030: }
//000031: }
IL_0111: ldarg.0
IL_0112: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_0117: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetResult()
IL_011c: nop
IL_011d: nop
IL_011e: ret
} // end of method <Foo>d__0::MoveNext
.method private hidebysig newslot virtual final
instance void SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine param0) cil managed
{
.custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 )
.override [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder AsyncCaptureVariables.Program/<Foo>d__0::<>t__builder
IL_0006: ldarg.1
IL_0007: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine)
IL_000c: ret
} // end of method <Foo>d__0::SetStateMachine
} // end of class <Foo>d__0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With