2013-08-15 2 views
10

Innerhalb einer async Methode werden alle lokalen Variablen weg gespeichert, so dass, wenn der Thread weiterhin await Zugriff auf die Werte hat. Gibt es eine Möglichkeit anzugeben, welche Werte nach der await wirklich benötigt werden?Kann ich angeben, welche Variablen ich über die Beendigung einer Wartezeit hinaus beibehalten möchte?

Zum Beispiel:

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 habe ich 7 lokale Variablen deklariert, aber nur 2 von ihnen verwenden, nach dem await, gibt es eine Attribut ich mit meiner Variablen dekorieren kann, um anzuzeigen, dass ich nur den Einsatz beabsichtigen firstName und city nachdem die await abgeschlossen ist?

Hinweis: Dies ist ein künstliches Beispiel, aber es scheint, als könnte es nützlich sein, den Speicher von potenziell großen Datenbrocken einzudämmen, wenn sie nicht benötigt werden, wenn der nächste Thread die Arbeit beendet.

+0

Ich denke, das Ding an den Compiler besser links ist. – Diryboy

Antwort

6

Nein, das geht nicht. (Abgesehen von den offensichtlichen Lösungen, sie in separate Methoden aufzuteilen oder auf null zu setzen).

Der Compiler ist in diesem Szenario nicht vollständig optimiert; Es kann mehr Variablen erfassen, als es benötigt, und sie können länger als nötig beibehalten werden. Dies ist wahrscheinlich etwas, das Microsoft in Zukunft optimieren wird.

+0

Vielleicht werden sie es in C# 6 ansprechen, wird abwarten und sehen. :-) –

0

Sie können Bereiche erstellen, indem Sie geschweifte Klammern im Code einfügen, aber immer, wenn etwas nicht mehr referenziert wird, wird der Compiler das trotzdem erfassen. Dazu

{ //start of scope 
    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(); 
}//end of scope 

Es gibt andere Dinge, die in Betracht gezogen werden könnten, wie wenn Sie Methoden erstellen können logisch Dinge zu teilen, als in meiner Meinung, dass eine bessere Option ist. Obwohl es auch nicht schadet, es auf diese Weise zu tun.

+0

Es ist mir nicht klar, wie das Hinzufügen eines Oszilloskops irgendeinen Effekt hätte. –

+0

Beim Hinzufügen eines Bereichs wird nichts auf Null gesetzt. Die Einheimischen sind nicht einmal mehr echte Einheimische. Sie werden in Felder in einer Compiler-generierten Implementierung von 'IAsyncStateMachine' transformiert. –

+0

Lässt man es so nennen, da die Variablen nach der schließenden Klammer aus dem Geltungsbereich herausfallen und daher gut für GC sein werden. – Ehsan

3

Sie können Ildasm.exe in Ihrem Programm ausführen, um zu sehen, welchen Code der Compiler generiert. Ich habe versucht, dies zu tun, aber leider meine IL-Fähigkeiten sind ein bisschen fehlt, aber Sie können sehen, dass alle lokalen Variablen als Felder der generierten <Foo>d__0 Klasse erfasst werden. Vor diesem Programm:

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(); 
     } 
    } 
} 

Der Compiler erzeugt so etwas wie die folgenden zum Teil umgewandelt 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 
+0

+1 für die detaillierte Aufschlüsselung dessen, was hinter den Kulissen vor sich geht, war nicht klar, dass eine Zustandsmaschine verwendet wurde, um die Werte zu speichern. –

Verwandte Themen