35

.NETでは非同期データベース呼び出しは悪い考えであることを示す記事がいくつかあります。

C#非同期CTPには、System.Data.SqlClient.SqlCommandと呼ばれる拡張子がありExecuteReaderAsyncます。既存のコードに対して以下のような操作があります。

var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString;

using (var conn = new SqlConnection(connectionString)) {
    using (var cmd = new SqlCommand()) {

        cmd.Connection = conn;
        cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount";
        cmd.CommandType = System.Data.CommandType.StoredProcedure;

        conn.Open();

        var reader = cmd.ExecuteReader();
        while (reader.Read()) {

            //do the reading

        }

        conn.Close();
    }
}

私のコードには、このような操作がいくつかあります。だから、私はそれらを非同期に変換することを考えています。

しかし一方で、私はこのアプローチにあまり魅力を感じていません(多分私は正しい方向を見ていません、誰が知っていますか!)。

それで、ここでこの新しい非同期プログラミングモデルを使用することの不利な点はありますか?

編集:

以下のようにコードをリファクタリングすると仮定します。

public async Task<IEnumerable<Foo>> GetDataAsync() { 

    List<Foo> foos = new List<Foo>();

    var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString;

    using (var conn = new SqlConnection(connectionString)) {
        using (var cmd = new SqlCommand()) {

            cmd.Connection = conn;
            cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount";
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            conn.Open();

            var reader = await cmd.ExecuteReaderAsync();
            while (reader.Read()) {

                //do the reading
                //create foos

            }

            conn.Close();
        }
    }

    return foos;

}

awaitキーワードから理解できる限り、それはその後にあるコードを継続として変換します。また、awaitキーワードをヒットすると、操作ステータスに関係なく、すぐに呼び出し元に戻ります。終了すると、戻ってきて継続コードを起動します。

これが私が考えていることです。

4

2 に答える 2

61

私はこれについてリッカに同意しません。非同期DBコマンドは優れているだけでなく、スケール、スループット、および遅延を実現するために重要です。スレッドプールの立ち上げ時間に関する彼の反対意見は、トラフィック量が少ないWebサーバーにのみ当てはまります。

トラフィックが多い状況(重要なのはこれだけです)では、スレッドプールは新しいスレッドの「注入」を待つ必要はありません。SQLコマンドを非同期で実行することは、Webサーバーの要求/スレッドの状態の観点からだけでなく、要求の存続期間/待機時間の合計の観点からも重要です。相関のないDB呼び出しは、順次ではなく並列で実行できます。これだけでも、通常、ユーザーが経験するHTTPリクエストのレイテンシが劇的に改善されます。つまり、ページの読み込みが速くなります。

Asynchronous Processing=trueただし、アドバイスがあります。接続文字列を有効にするまで、SQLコマンドは真に非同期ではありません。これは設定されていませんが(デフォルトでは設定されていません。編集:.NET Framework <4.5 Asynchronous Processing以降は不要です)、「非同期」呼び出しは偽物にすぎません。呼び出しはスレッドを起動し、そのBeginExecuteReaderスレッドをブロックします。接続文字列で真の非同期処理が有効になっている場合、呼び出しは真に非同期であり、コールバックはIOの完了に基づいています。

注意:非同期SQLコマンドは、最初の結果がクライアントに返されるとすぐに完了し、情報メッセージは結果としてカウントされます。

create procedure usp_DetailsTagsGetAllFromApprovedPropsWithCount
as
begin
print 'Hello';
select complex query;
end

あなたは非同期のすべての利点を失いました。はprint、クライアントに返送される結果を作成します。これにより、非同期コマンドが完了し、クライアントでの実行が再開され、「reader.Read()」が続行されます。これで、複雑なクエリが結果の生成を開始するまでブロックされます。あなたは「誰がprint手続きをするのですか?」と尋ねます。しかし、printは他の何かに偽装されている可能性があります。おそらく、最初にを発行せずINSERTに実行されるのと同じくらい無邪気なものです。SET NOCOUNT ON

于 2012-02-24T16:48:37.913 に答える
0

次の質問に答えられなかったことに気づきました。

それで、ここでこの新しい非同期プログラミングモデルを使用することの不利な点はありますか?

非常に最小限欠点(マイナーCPU /マイナーメモリafaik)は、awaitステートメント別のスレッドで実行された後に実行されるコードの可能性があるため、現在実行中の状態を格納するステートマシンが存在することです。作業の継続を別のスレッドで処理できるようにするためのスレッド。await / asyncステートマシンの詳細については、Dixinのブログ-C#async / await(1)コンパイルについてをご覧ください

于 2018-01-26T18:55:06.227 に答える