3

私は非同期プログラミングが苦手なので、質問は低レベルかもしれません。

ASP.NET MVC 4 Dev で Async CTP を使用して、以下の非同期メソッドを作成しました。プレビュー:

public class Movie
{
    public string Title { get; set; }
    public string Url { get; set; }
    public string BoxArtUrl { get; set; }
}

public class MovieM {

    public IEnumerable<Movie> M2009 { get; set; }
    public IEnumerable<Movie> M2010 { get; set; }
    public IEnumerable<Movie> M2011 { get; set; }
}

public class HomeController : AsyncController  {

    public async Task<ActionResult> GetMoviesM()  {

        var profiler = MiniProfiler.Current; // it's ok if this is null

        var pageSize = 1000;
        var imageCount = 0;

        using (profiler.Step("Start pulling data (Async) and return it")) { 

            var m2009 = await QueryMoviesAsync(2009, imageCount, pageSize);
            var m2010 = await QueryMoviesAsync(2010, imageCount, pageSize);
            var m2011 = await QueryMoviesAsync(2011, imageCount, pageSize);

            return View(new MovieM { 
                M2009 = m2009,
                M2010 = m2010,
                M2011 = m2011
            });
        }
    }

    XNamespace xa = "http://www.w3.org/2005/Atom";
    XNamespace xd = "http://schemas.microsoft.com/ado/2007/08/dataservices";
    XNamespace xm = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

    string query = "http://odata.netflix.com/Catalog/Titles?$filter=ReleaseYear eq {0}&$skip={1}&$top={2}&$select=Url,BoxArt";

    async Task<IEnumerable<Movie>> QueryMoviesAsync(int year, int first, int count)  {

        var client = new WebClient();
        var url = String.Format(query, year, first, count);
        var data = await client.DownloadStringTaskAsync(new Uri(url));
        var movies =
            from entry in XDocument.Parse(data).Descendants(xa + "entry")
            let properties = entry.Element(xm + "properties")
            select new Movie
            {
                Title = (string)entry.Element(xa + "title"),
                Url = (string)properties.Element(xd + "Url"),
                BoxArtUrl = (string)properties.Element(xd + "BoxArt").Element(xd + "LargeUrl")
            };
        return movies.AsEnumerable();
    }
}

コードは問題なく動作します。デスクトップ アプリ (たとえば、WPF アプリ) で同じ関数を実行すると、明確なパフォーマンスの違いが見られます。UI はブロックされず、データは利用可能になると即座に画面にプッシュされます。

しかし、Web アプリケーションでは、実際には違いがわかりません。sync と同じ関数も作成しましたが、どちらもほぼ同じです。

私が知りたいのは、次のことです。

  1. Intel Core 2 Duo CPU T5750 2.00GHzを搭載したマシンでこのアプリを実行しています。プロセッサの数は C# の非同期スレッドのパフォーマンスに影響しますか?
  2. ここで Web アプリケーションの観点から何か間違ったことをしていますか?
4

2 に答える 2

3

デスクトップ アプリ (たとえば、WPF アプリ) で同じ関数を実行すると、明確なパフォーマンスの違いが見られます。UI はブロックされず、データは利用可能になると即座に画面にプッシュされます。

これはよくある誤解です。投稿したメソッドは、同期の同等のものよりもわずかに遅くなりますが、UI アプリではより応答性高く、パフォーマンスが向上しているように見えます。

ASP.NET シナリオでは、すべての非同期要求が完了したときにのみページがレンダリングされます。それが違いが見えない理由です。

リクエストを並列化することで、実際にパフォーマンスを向上させることができます。

var m2009Task = QueryMoviesAsync(2009, imageCount, pageSize);
var m2010Task = QueryMoviesAsync(2010, imageCount, pageSize);
var m2011Task = QueryMoviesAsync(2011, imageCount, pageSize);
await Task.WhenAll(m2009Task, m2010Task, m2011Task);
var m2009 = await m2009Task;
var m2010 = await m2010Task;
var m2011 = await m2011Task;

これにより、デスクトップと ASP.NET の両方のパフォーマンスが向上します。

元のコードでは、シリアル構成 (一度awaitに 1 つずつ) を使用しています。この場合、コードは非同期で実行されますが、要求はそれ以上早く完了しません。asyncこのように/を使用することにはまだ利点がありますawait。要求が ASP.NET スレッドを拘束しないため、サービスをさらにスケールアップできます。UI の世界では、UI スレッドが拘束されないため、より応答性が高くなります。ただし、ASP.NET と UI の両方で、メソッドを完了するまでの合計時間は、 .GetMoviesMasync

並列構成 (Task.WhenAllまたはを使用Task.WhenAny) ではGetMoviesM、要求が並列で実行されるため、全体としてより高速に実行できます。さらに、前述のスレッドの利点も得られます。

この場合、プロセッサの数は関係ありません。Task.RunI/O を実行しているときではなく、スレッド プール (例: ) で処理を実行しているときにのみ機能します。(これは単純化されていますが、十分に真実です)。

于 2011-12-07T01:54:41.307 に答える
0

いくつかのコメント。

まず、WebClient はデフォルトで、サーバーごと、セッションごとに 2 つの接続のみを開きます。これは明らかにスケーリング能力に影響を与えるため、それを変更することをお勧めします [ WebClient で 2 つの接続制限をプログラムで削除する方法を参照してください]。

第二に、コントローラー メソッドと QueryMoviesAsync メソッド内の両方で async を使用する利点があるかどうかはわかりません。

3 番目に、WebClient は IDisposable を実装しているため、using(..) ステートメントで使用する必要があります。そうしないと、スケーラビリティにも影響する可能性があります。

上記のすべての変更を考慮し、元の質問に答えるために、はい、コードは実行時に複数のプロセッサ/コアにわたってスケールアウトする必要があります。これは ASP.NET/IIS のデフォルトです。

于 2011-12-06T06:33:39.233 に答える