2013-08-15 7 views
10

W metodzie async wszystkie zmienne lokalne są przechowywane w oddaleniu, więc gdy dowolny wątek będzie kontynuowany po uzyskaniu dostępu do wartości, await. Czy jest jakiś sposób wskazania, które wartości są naprawdę potrzebne po await?Czy mogę określić, które zmienne chcę utrzymywać po zakończeniu oczekiwania na kontynuację?

Na przykład:

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

Więc zadeklarowały 7 zmiennych lokalnych, ale wykorzystać tylko 2 z nich po await, czy istnieje atrybut mogę ozdobić moje zmienne z celu wskazania, że ​​mam zamiar wyłącznie do użytku firstName i city po zakończeniu await?

Uwaga: Jest to wymyślny przykład, ale wydaje się, że może być korzystne, aby ograniczyć przechowywanie potencjalnie dużych porcji danych, jeśli nie są one potrzebne, gdy pojawi się następny wątek, aby zakończyć pracę.

+0

myślę, że to jest to lepiej pozostawić do kompilatora. – Diryboy

Odpowiedz

6

Nie, nie możesz. (Poza oczywistymi rozwiązaniami dzielenia ich na osobne metody lub ustawiania ich na null).

Kompilator nie jest w pełni zoptymalizowany w tym scenariuszu; może uchwycić więcej zmiennych niż potrzebuje i może utrzymać je dłużej niż to konieczne. Jest to prawdopodobnie coś, co Microsoft zoptymalizuje w przyszłości.

+0

Może to adres w C# 6, będzie czekać i zobacz. :-) –

0

Możesz tworzyć zakresy za pomocą dodanych nawiasów klamrowych w kodzie, ale gdy coś nie zostanie odwołane, kompilator i tak to zbierze. zrobić to

{ //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 

Są inne rzeczy, które mogą być brane pod uwagę, gdyby można utworzyć metody logicznie podzielić rzeczy niż w moim zdaniem jest lepszym rozwiązaniem. Chociaż nie ma nic złego w robieniu tego w ten sposób.

+0

Nie jest dla mnie jasne, w jaki sposób dodanie zakresu może przynieść jakiś efekt. –

+0

Dodanie zakresu nie powoduje, że cokolwiek zostanie ustawione na wartość null. Miejscowi nie są już tak naprawdę tubylcami. Są one przekształcane na pola na wygenerowanej przez kompilator implementacji 'IAsyncStateMachine'. –

+0

Wywołajmy to w ten sposób, ponieważ zmienne wyjdą poza zakresem po nawiasie zamykającym, więc będą dobre do zebrania GC. – Ehsan

3

Możesz uruchomić Ildasm.exe na swoim programie, aby zobaczyć, jaki kod generuje kompilator. Próbowałem to zrobić, ale niestety brakuje mi trochę umiejętności obsługi komputera, ale widać, że wszystkie zmienne lokalne są przechwytywane jako pola wygenerowanej klasy <Foo>d__0. Biorąc pod uwagę ten 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(); 
     } 
    } 
} 

Kompilator generuje coś jak następuje częściowo zamieniane na kod C#:

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 dla szczegółowego podziału tego, co dzieje się za kulisami, nie zdawałem sobie sprawy, że do przechowywania wartości używany był automat stanów. –

Powiązane problemy