6

関数のインライン化は、関数呼び出しサイトを呼び出し先の本体に置き換えるコンパイラの最適化です。この最適化は、通常の C# 関数でサポートされています。

C# 5.0 でasync-awaitパターンをサポートする非同期async関数には、修飾子を含む特別な宣言があり、戻り値をTask<>.

非同期関数もインライン化できますか?

例:

次の関数があるとします。

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

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

次のように最適化できますか。

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

追加クレジット:

サポートされている場合、何がインライン化されているかを誰が決定できますか? コンパイラ?ジット?自分?

サポートされていない場合、これについて心配し、読みやすくするために時々追加する過剰なラッパーを避ける必要がありますか?

4

2 に答える 2

4

によって引き起こされる変換の複雑さを考慮するasync/awaitと、コードがインライン化可能ではないと思いasync/awaitます。メソッドが隠しクラスで変換され、コードがステート マシンになり、コードのさまざまな部分が異なる状態になります。

例を挙げると、次のCalleeAsync()ようなモンスターに変換される単純なメソッド:

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

(このマシンには、Async CTP を備えた Visual Studio 2010 がまだあります。.NET 4.5 では、生成されたコードが異なる可能性があることに注意してください)。

そのようなものはインライン化可能だと思いますか?

于 2013-09-02T07:34:12.137 に答える
1

C# コンパイラは、「単純な」 のかなりの量の IL コードを作成しますawait。xanatos は、C# に変換したときにその IL コードがどのように見えるかを既に示しました。JIT コンパイラ (インライン化を行うコンパイラ) にはインライン化に関する厳密な規則があるため、すべてのコードがインライン化されるとは思えません。

以下に、JIT のインライン化に関するいくつかの規則を示します (現在の JIT には当てはまらないかもしれませんが、良い出発点です)。ここで、すでに 2 つのルールに違反していることがわかります。32 バイトを超える IL コードと例外処理ブロックがあります。

于 2013-09-02T12:23:42.170 に答える