2

Excel スプレッドシートを生成するためのハイブリッド Excel Interop/EPPlus アプリは、実行するたびに徐々に遅くなります。

この理由を突き止めるために、ANTS Memory Profiler をダウンロードしてアプリを実行しました。

ANTS MP は、「CLR に読み込まれたアセンブリ」の詳細で、2 つの動的に生成されたアセンブリがあることを示しています。1 つは "InitializeExcelObjects()" メソッドにあります。これは、Excel.Application と関連オブジェクトを作成するため、理にかなっています。しかし、(おそらく?) アセンブリをロードする 2 番目の方法は次のとおりです。

private void WriteHeader(String shortName)
{
    const int LOGO_FIRST_ROW = 1;
    const int LOGO_LAST_ROW = 5;
    var rowRngUnitName = _xlSheet.Range[_xlSheet.Cells[UNIT_NAME_ROW, 1], _xlSheet.Cells[UNIT_NAME_ROW, 3]];
    rowRngUnitName.Merge(Type.Missing);
    rowRngUnitName.Font.Bold = true;
    rowRngUnitName.Font.Size = UNIT_NAME_FONT_SIZE;
    rowRngUnitName.Value2 = shortName;

    var rowRngRptTitle = _xlSheet.Range[_xlSheet.Cells[REPORT_TITLE_ROW, 1], _xlSheet.Cells[REPORT_TITLE_ROW, 5]];
    rowRngRptTitle.Merge(Type.Missing);
    rowRngRptTitle.Font.Size = REPORT_TITLE_ROW_FONT_SIZE;
    rowRngRptTitle.Font.Bold = true;
    rowRngRptTitle.Value2 = ProduceUsageByMonthLabel;

    var rowRngRptAdvisory = _xlSheet.Range[_xlSheet.Cells[REPORT_ADVISORY_ROW, 1], _xlSheet.Cells[REPORT_ADVISORY_ROW, 4]];
    rowRngRptAdvisory.Merge(Type.Missing);
    rowRngRptAdvisory.Font.Size = REPORT_ADVISORY_ROW_FONT_SIZE;
    rowRngRptAdvisory.Value2 = ProductsHiddenAdvisoryLabel;

    // col 5A (ANNUAL_CONTRACT_PRODUCTS_ROW)
    var rowRngContractProducts = _xlSheet.Range[
        _xlSheet.Cells[ANNUAL_CONTRACT_PRODUCTS_ROW, ITEMDESC_COL],
        _xlSheet.Cells[ANNUAL_CONTRACT_PRODUCTS_ROW, ITEMDESC_COL]];
    rowRngContractProducts.Merge(Type.Missing);
    rowRngContractProducts.Font.Size = ANNUAL_CONTRACT_PRODUCTS_LEGEND_FONT_SIZE;
    rowRngContractProducts.Font.Bold = true;
    rowRngContractProducts.HorizontalAlignment = XlHAlign.xlHAlignCenter;
    rowRngContractProducts.VerticalAlignment = XlVAlign.xlVAlignCenter;
    rowRngContractProducts.Value2 = AnnualContractProductsLabel;
    Borders border = rowRngContractProducts.Borders;
    border.Weight = XlBorderWeight.xlThin;
    border.LineStyle = XlLineStyle.xlContinuous;

    // Logo
    var logoRange = _xlSheet.Range[
        _xlSheet.Cells[LOGO_FIRST_ROW, _grandTotalsColumn], _xlSheet.Cells[LOGO_LAST_ROW, _grandTotalsColumn + 1]];
    ReportRunnerConstsAndUtils.PlacePicture(_logo, logoRange);
}

...そして、関係するのはこれです:

var rowRngUnitName = _xlSheet.Range[_xlSheet.Cells[UNIT_NAME_ROW, 1], _xlSheet.Cells[UNIT_NAME_ROW, 3]];

...これは異常なことは何もしません (範囲はコード内のいたるところに割り当てられているため、これが他のものとは異なり、アセンブリのスポーナーと見なされるのはなぜですか)?

範囲が割り当てられたのはこれが初めてだからですか? それが完了すると、一部のアセンブリが動的に読み込まれますか (一度だけ)?

問題のメソッドを呼び出すコードは次のとおりです。

public bool GenerateProduceUsageRpt()
{
    const int SLEEPY_TIME = 10000;
    const int MONTH_SPLIT_CUTOFF = 7;
    try
    {
        InitializeExcelObjects();
        _monthsInReport = ReportRunnerConstsAndUtils.GetMonthsInReport(_monthBegin, _monthEnd, _beginYearStr, _endYearStr);
        _grandTotalsColumn = _monthsInReport + 3;
        _grandTotalsColumnPivotTable = _grandTotalsColumn - 1;

        _lastMonthColumn = _grandTotalsColumn - 1;

        InitializeYearAndMonthVals();

        try
        {
            System.Windows.Forms.Application.DoEvents();
            if (_xlSheet != null)
            {
                _xlSheet.Name = ProduceUsageByMonthSheetName;
                _xlPivotDataSheet.Name = ProduceUsageByMonthPivotTableSheetName;
                _xlPivotTableSheet.Name = "PivotTable";

                WriteHeader(_unit);
                WriteColumnHeadings();
                . . .

これは予想されることですか (この時点でアセンブリが動的に読み込まれるため)、それとも、経験しているパフォーマンスが徐々に悪化していることと関係があるのでしょうか?

アップデート

Glenn Ferrie のコメントに基づいて、この方法は興味深いかもしれません。

// From Jürgen Tschandl at http://stackoverflow.com/questions/7413107/excel-image-in-a-cell
internal static void PlacePicture(Image picture, Range destination)
{
    Worksheet ws = destination.Worksheet;
    Clipboard.SetImage(picture);
    ws.Paste(destination, false);
    Pictures p = ws.Pictures(Missing.Value) as Pictures;
    if (p != null)
    {
        Picture pic = p.Item(p.Count) as Picture;
        ScalePicture(pic, (double)destination.Width, (double)destination.Height);
    }
}
4

0 に答える 0