2013-09-02 9 views
6

Inlining functions ist eine Compiler-Optimierung, die die Funktionsaufruf-Site durch den Body des Angerufenen ersetzt. Diese Optimierung wird für regular C# functions unterstützt.Können Async-Funktionen inline sein?

Async Funktionen, die das async-await Muster in C# 5.0 haben eine besondere Erklärung zu unterstützen, die die async Modifikator und Verpackung Rückgabewerte mit Task<> beinhaltet.

Können asynchrone Funktionen auch inline sein?

Beispiel:

Angenommen, ich habe diese Funktionen:

private async Task<int> CallerAsync() { 
    return await SomeOperationAsync(); 
} 

Extra Credit:

private async Task<int> CalleeAsync() { 
    return await SomeOperationAsync(); 
} 

private async Task<int> CallerAsync() { 
    return await CalleeAsync(); 
} 

Konnten sie optimiert werdenWenn es unterstützt wird, wer kann entscheiden, was inline ist? Der Compiler? Die JIT? mich?

Wenn es nicht unterstützt wird, sollte ich mich darum sorgen und übermäßige Wrapper vermeiden, die ich manchmal für die Lesbarkeit hinzufüge?

+0

Keine Notwendigkeit, eine weitere Aufgabe zu erstellen. 'private Task CalleAsync() { Rückgabe SomeOperationAsync(); } ' – I4V

+0

@ I4V Natürlich. Beachten Sie, dass dies nur ein simples Beispiel ist. Wirkliche Lebensszenarien werden wahrscheinlich etwas komplizierter sein :) – talkol

Antwort

4

In Anbetracht der Komplexität der von async/await verursacht Transformationen, ich glaube nicht, der Code ist inlineable: async/await führen, dass Ihre Methode in einer versteckten Klasse tranformed werden und der Code wird eine Zustandsmaschine, mit verschiedenen Teilen des Codes immer verschiedene Staaten.

ein Beispiel zu geben, ist eine einfache Methode, wie CalleeAsync() ein Monster wie verwandelt:

[CompilerGenerated] 
private sealed class <CalleeAsync>d__2 
{ 
    private int <>1__state; 
    private bool $__disposing; 
    public System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> $builder; 
    public Action <>t__MoveNextDelegate; 
    public Program <>4__this; 
    private TaskAwaiter<int> <a1>t__$await4; 
    public void MoveNext() 
    { 
     int result2; 
     System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> asyncTaskMethodBuilder; 
     try 
     { 
      int num = this.<>1__state; 
      if (num != 1) 
      { 
       if (this.<>1__state == -1) 
       { 
        return; 
       } 
       this.<a1>t__$await4 = this.<>4__this.SomeOperationAsync().GetAwaiter<int>(); 
       if (!this.<a1>t__$await4.IsCompleted) 
       { 
        this.<>1__state = 1; 
        this.<a1>t__$await4.OnCompleted(this.<>t__MoveNextDelegate); 
        return; 
       } 
      } 
      else 
      { 
       this.<>1__state = 0; 
      } 
      int result = this.<a1>t__$await4.GetResult(); 
      this.<a1>t__$await4 = default(TaskAwaiter<int>); 
      result2 = result; 
     } 
     catch (Exception exception) 
     { 
      this.<>1__state = -1; 
      asyncTaskMethodBuilder = this.$builder; 
      asyncTaskMethodBuilder.SetException(exception); 
      return; 
     } 
     this.<>1__state = -1; 
     asyncTaskMethodBuilder = this.$builder; 
     asyncTaskMethodBuilder.SetResult(result2); 
    } 
    [DebuggerHidden] 
    public void Dispose() 
    { 
     this.$__disposing = true; 
     this.MoveNext(); 
     this.<>1__state = -1; 
    } 
    [DebuggerHidden] 
    public <CalleeAsync>d__2(int <>1__state) 
    { 
     this.<>1__state = <>1__state; 
    } 
} 

(beachten Sie, dass auf dieser Maschine Ich habe noch das Visual Studio 2010 mit dem Async CTP, mit .NET 4.5 der generierte Code könnte anders sein).

Denken Sie, dass so etwas inlineable ist?

+2

Nun, wenn ich mit dem gehen müsste, was ich dachte, würde ich sagen, dass die meisten Compiler-Optimierungen unmöglich waren :) Was wäre, wenn der Compiler versucht, vor dem Kompilieren in diese Zustandsmaschine zu inline zu gehen Monster?Ich kann sehen, dass dies auf einer Pre-Prozessor-Ebene passiert (wenn eine existierte), obwohl ich nicht wirklich weiß, wovon ich rede – talkol

+0

@talkol Der C# -Compiler macht keine besonderen Dinge und ändert nur selten zu viel Code . Ich denke nicht, dass es inlining (ich denke, es ist die JIT, die den Code inline) – xanatos

1

Der C# -Compiler erstellt ziemlich viel IL-Code für ein "einfaches" await, xanatos zeigte bereits, wie der IL-Code aussehen würde, wenn er zurück in C# übersetzt wird. Da der JIT-Compiler (der Inliner ist) strenge Regeln für das Inlining hat, bezweifle ich, dass er den ganzen Code einbinden wird.

Here sind einige Regeln für JIT-Inlining (diese sind möglicherweise nicht für die aktuelle JIT, aber sind ein guter Anfang). Hier kann ich bereits zwei verletzte Regeln sehen: Wir haben mehr als 32 Byte IL-Code und einen Ausnahmebehandlungsblock.

Verwandte Themen