2013-09-02 19 views
6

Inlining functions è un ottimizzazione del compilatore che sostituisce il sito di chiamata di funzione con il corpo del destinatario. Questa ottimizzazione è supportata per regular C# functions.Le funzioni asincrone possono essere allineate?

Async funzioni che supportano il modello async-await in C# 5.0 hanno una speciale dichiarazione che coinvolge i valori modificatori e ritorno avvolgente async con Task<>.

Anche le funzioni asincrone possono essere allineate?

Esempio:

Supponiamo che io sono queste funzioni:

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

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

potevano essere ottimizzati per:

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

Credit Extra:

Se è supportato, chi può decidere cosa è in linea? Il compilatore? Il JIT? me?

Se non è supportato, dovrei preoccuparmi di questo ed evitare i wrapper eccessivi che a volte aggiungo per la leggibilità?

+0

Non è necessario creare un'altra attività. 'private Task CalleeAsync() { return SomeOperationAsync(); } ' – I4V

+0

@ I4V Naturalmente. Tieni presente che questo è solo un esempio concettuale semplicistico. Probabilmente gli scenari di vita reale saranno leggermente più complicati :) – talkol

risposta

4

Considerata la complessità delle trasformazioni causate da async/await, non credo che il codice è inlineable: async/await causare il metodo da tranformed in una classe di nascosto e il codice diventa una macchina a stati, con le varie parti del codice divenire stati diversi.

Per fare un esempio, un metodo semplice come CalleeAsync() si trasforma in un mostro come:

[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; 
    } 
} 

(si noti che su questa macchina ho ancora il Visual Studio 2010 con l'Async CTP, con .NET 4.5 il codice generato potrebbe essere diverso).

Pensi che qualcosa del genere sia ineliminabile?

+2

Beh, se dovessi andare con quello che pensavo, suppongo che direi che la maggior parte delle ottimizzazioni del compilatore erano impossibili :) E se il compilatore avesse provato a compilare prima di compilarlo in questo stato macchina mostro?Posso vedere questo accadendo a livello di pre-processore (se ne esisteva uno), anche se non so davvero di cosa sto parlando – talkol

+0

@talkol Il compilatore C# non fa cose particolarmente elaborate e raramente modifica troppo codice . Non penso che faccia inlining (penso che sia la JIT che delinea il codice) – xanatos

1

Il compilatore C# creerà piuttosto codice IL per un "semplice" await, xanatos ha già mostrato come sarebbe il codice IL quando viene tradotto in C#. Dal momento che il compilatore JIT (che è quello che esegue l'inlining) ha delle regole rigide per l'inlining, dubito che inline tutto quel codice.

Here sono alcune regole per l'inlining JIT (quelle potrebbero non essere vere per l'attuale JIT, ma sono un buon inizio). Qui posso già vedere violate due regole: abbiamo più di 32 byte di codice IL e un blocco di gestione delle eccezioni.

Problemi correlati