0

WriteAsync間接的に何度も呼び出す簡単なパフォーマンステストがあります。WriteAsync以下に示すように実装されている限り、それは合理的に機能します。ただし、にインラインWriteByte化するWriteAsyncと、パフォーマンスが約7倍低下します。

(明確にするために:私が行う唯一WriteByteの変更は、呼び出しを含むステートメントをの本文に置き換えることですWriteByte。)

なぜこれが起こるのか誰かが説明できますか?私はReflectorで生成されたコードの違いを見てきましたが、それが巨大なパフォーマンスヒットを説明するほど完全に異なるものは何も私を驚かせませんでした。

public sealed override async Task WriteAsync(
    byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
    var writeBuffer = this.WriteBuffer;
    var pastEnd = offset + count;

    while ((offset < pastEnd) && ((writeBuffer.Count < writeBuffer.Capacity) ||
        await writeBuffer.FlushAsync(cancellationToken)))
    {
        offset = WriteByte(buffer, offset, writeBuffer);
    }

    this.TotalCount += count;
}
private int WriteByte(byte[] buffer, int offset, WriteBuffer writeBuffer)
{
    var currentByte = buffer[offset];

    if (this.previousWasEscapeByte)
    {
        this.previousWasEscapeByte = false;
        this.crc = Crc.AddCrcCcitt(this.crc, currentByte);
        currentByte = (byte)(currentByte ^ Frame.EscapeXor);
        ++offset;
    }
    else
    {
        if (currentByte < Frame.InvalidStart)
        {
            this.crc = Crc.AddCrcCcitt(this.crc, currentByte);
            ++offset;
        }
        else
        {
            currentByte = Frame.EscapeByte;
            this.previousWasEscapeByte = true;
        }
    }

    writeBuffer[writeBuffer.Count++] = currentByte;
    return offset;
}
4

1 に答える 1

1

asyncメソッドは、コンパイラによって巨大なステートマシンに書き直されます。これは、を使用するメソッドと非常によく似ていますyield return。すべてのローカルは、ステートマシンのクラスのフィールドになります。コンパイラーは現在、これをまったく最適化しようとしないため、最適化はコーダー次第です。

レジスターに喜んで座っていたであろうすべてのローカルは、現在、メモリーから読み取られ、メモリーに書き込まれています。同期コードをasyncメソッドから同期メソッドにリファクタリングすることは、非常に有効なパフォーマンスの最適化です。逆のことをしているだけです。

于 2012-12-14T21:25:01.010 に答える