28

私は私のasp.net MVC 4アプリケーションで優れたダウンロードをしています。エクスポートボタンをクリックすると、以下のコントローラメソッドが呼び出されます。非同期にする必要があるので、asyncを使用してここで待ちます。

public async Task<ActionResult> GenerateReportExcel()
    {
        ExcelGenerator excel = new ExcelGenerator();
        var filePath = await excel.ReportExcelAsync(midyearReportViewModel);
        System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
        response.ClearContent();
        response.Clear();
        response.ContentType = "text/plain";
        response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.xlsx;", PdaResource.ReportFileName)); 
        response.TransmitFile(filePath);
        response.Flush();
        response.End();
        return PartialView("_MidYearReportPartial", midyearReportViewModel);
    }

このメソッドは、以下に示すようにExcelジェネレータメソッドReportExcelAsyncをinturnで呼び出します。

public async Task<string> ReportExcelAsync(MidYearReportViewModel _midyearAnnualviewModel)
    {
        string fileName = "MidYearReport";
        string finalXcelPath = string.Empty;
        string currentDirectorypath = new DirectoryInfo(HttpContext.Current.Server.MapPath("~/Export")).ToString();
        finalXcelPath = string.Format("{0}\\{1}.xlsx", currentDirectorypath, fileName);
        if (System.IO.File.Exists(finalXcelPath))
        {
            System.IO.File.Delete(finalXcelPath);
        }
        var newFile = new FileInfo(finalXcelPath);
        using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
        {
            using (var package = new ExcelPackage(newFile))
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(resxSet.GetString("ReportMYMidYearExcelSheetName"));
                for (int i = 1; i <= header.Count(); i++)
                {
                    worksheet.Cells[1, i].Value = header[i - 1];
                    worksheet.Cells[1, i].Style.Font.Bold = true;
                    worksheet.Cells[1, i].Style.Fill.PatternType = ExcelFillStyle.Solid;
                    worksheet.Cells[1, i].Style.Font.Color.SetColor(Color.White);
                    worksheet.Cells[1, i].Style.Fill.BackgroundColor.SetColor(Color.DimGray);
                }
                package.Save();
            }
        }
        return finalXcelPath; 
    }

しかし、Warningという警告メッセージが出ます。

この非同期メソッドには 'await'演算子がなく、同期的に実行されます。   ノンブロッキングAPI呼び出しを待つために 'await'演算子を使うことを検討してください。   バックグラウンドスレッドでCPUバウンドの作業を行う場合は、 'Task.Run(...)'を待つ

。私は何か悪いことをしていますか?私のコードはうまく動き、私はExcelをダウンロードすることができます。

1 답변


59

私は何か悪いことをしていますか?

まあ、あなたは本当に非同期的に何かをしているのではありません。きみのReportExcelAsyncそれは持っていないので、メソッドは完全に同期ですawait式そうGenerateReportExcel電話しますReportExcelAsyncこれは同期的に実行され、その後完了したタスクを返します。現時点で行ったことは、実装に使用されるステートマシンなどを作成するためのわずかなオーバーヘッドを追加することだけです。async/await

なぜそれが実際に非同期で起こると予想したのかは明確ではありませんが、待機/非同期が実際に何をするのかの誤解だと思います。それしない自動的に新しいスレッドを起動します。非同期APIを作成して使用するのがはるかに簡単になります。

今1つのオプションは単に変更したいということですReportExcelAsync同期メソッドにReportExcelを返すstring)と呼び出しコードでそのための新しいタスクを作成します。

var filePath = await Task.Run(excel.ReportExcel);

しかし、これが実際に多くの利益をもたらすことは明らかではありません。あなたはWebアプリを書いているので、レスポンスがこのように早く配信されるわけではありません - あなたは事実上単にシフト作業が行われているスレッド

あなたは言う:

非同期にする必要があるので

...でも理由はありませんなぜそれは非同期的に行われる必要があります。この場合の同期アプローチの何が問題になっていますか?非同期性は適切な場合には素晴らしいですが、あなたの場合ではないと思います。


  • var filePath = await excel.ReportExcelAsync(midyearReportViewModel);この行は無効です。やっている? 2行目 - stevethethread
  • @stevethethread:それは物事を非同期的にしているでしょうもし ReportExcelAsync本当に非同期でした - しかしそうではありません。これは警告を生成するメソッドです。await式 - Jon Skeet
  • @Skeet私の目的は、エクセルを生成し、パスを非同期的に返すことでした。 - Jayason
  • @ user2988112:「非同期的に」という言葉をあなたが理解しているのではないでしょうか。私のと同じではありません。あなたがしていることはすべて同期的です - 非同期性がもたらされることをどこで期待していましたか、そしてそれが持っていることをどのような具体的な利益を期待しましたか?何問題あなたは実際にここで解決しようとしていますか? - Jon Skeet
  • @ user2988112:どうしてですか?まだやるべきことはたくさんありますが、それはすべてローカルで行われています。スレッドを解放しているのと同じではありません。あなたが非同期を魔法の弾丸として考えているように感じます - それは実際にはそうではありません。あなたは、実際の非同期がどこから来るのかを考えなければなりません。たとえば、データベースからデータを非同期的に取得したり、必要なスレッド数を減らすことができる非同期IOを実行することができますが、それ以外の方法では役に立たないと思います。あなたは実際にいますか持ってる現時点でパフォーマンスの問題? - Jon Skeet

リンクされた質問


関連する質問

最近の質問