Показать сообщение отдельно
Старый 29.11.2011, 11:45   #12  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Кстати, иногда можно слышать мнение, что кешированием в памяти чего-либо можно решить большинство проблем производительности.
К сожалению, это не всегда так. Серебряной пули нет. Кривой алгоритм может поставить на колени даже память с мощным процессором.

Второй пример нелинейности при обработке накладной по закупке :
Стек вызовов :
...
PurchFormLetter.run
PurchFormLetter.createJournal
PurchFormLetter.insertJournal
PurchFormLetter_Invoice.updateNow
PurchFormLetter_Invoice.updateInventory
MarkupAdjustment::adjustInvoice
ledgerVoucherObject.postCurrencyDiff

в методе ledgerVoucherObject.postCurrencyDiff есть вызовы методов
ledgerVoucherObject.listCurrencyAmountCur
ledgerBondClient.log2Table
ledgerBondClient.currentLog

Время выполнения каждого метода также квадратично зависит от числа строк в накладной. Но тут все немного хуже чем в первом случае, потому что для накладной из 1000 строк у меня получились дублирования мапов с одновременной фильтрацией путем перебора 8-9 тысяч элементов. Этого уже не выдерживает даже супербыстрый проц и память. Самое интересно что в мооем примере не было никаких накладных расходов и судя по всему выполнение метода MarkupAdjustment::adjustInvoice можно было вообще исключить.

Пока добавил такую оптимизацию :
X++:
/// <summary>
///    Calculates MST difference per transaction and generates an equalizing transaction.
/// </summary>
/// <param name="_ledgerVoucher">
///    The ledger voucher for the transaction.
/// </param>
/// <param name="_ledgerPostingType">
///    The posting type for the transaction.
/// </param>
/// <param name="_ledgerAccount">
///    The ledger account for the transaction.
/// </param>
/// <param name="_dimension">
///    A dimension.
/// </param>
/// <param name="_sourceTableId">
///    The table ID of the posting source.
/// </param>
/// <param name="_sourceRecId">
///    The record ID of the posting source
/// </param>
/// <param name="_transactionTxt">
///    A transaction text.
/// </param>
/// <param name="_level">
///    The level; option.
/// </param>
public void postCurrencyDiff(
    LedgerVoucher       _ledgerVoucher,
    LedgerPostingType  _ledgerPostingType,
    LedgerAccount      _ledgerAccount,
    Dimension          _dimension,
    tableId            _sourceTableId,
    recId              _sourceRecId,
    TransactionTxt     _transactionTxt,
    Integer            _level = 0)
{
    LedgerVoucherTransObject    ledgerVoucherTransObject;
    RecordSortedList            rsL;
    TmpLedgerTrans              tmpLedgerTrans;
    boolean                     more;
    // <GEEU>
    TmpLedgerBondLogTable_RU    logTable;
    LedgerBondTransObject_RU    bondTransObject;
    // </GEEU>
    boolean                     GRD_LoadedBondInfo = false;//+GRD_R4719_SpeedUpFormLetter_pkoz, pkoz, 24.11.2011


    rsL = this.listCurrencyAmountCur(_level);

    // <GEEU>

    // GRD_R4719_SpeedUpFormLetter_pkoz, pkoz, 24.11.2011 -->
    if (GRD5::isR4719_2())
    {
        // вынесли этот код (блок else) внутрь цикла ниже, так как вызовы ledgerBondClient.currentLog() и ledgerBondClient.log2Table(
        // могут быть сложны для расчета при большом числе строк в документе (нелинейные зависимости от числа строк содержатся )
        // а их результат иногда бывает и не нужен, поэтому раньше времени их не вызваем, а только по мере необходимости, т.е. на первом шаге цикла
    }
    else
    {
        if (ledgerBondClient)
        {
            logTable = ledgerBondClient.log2Table(ledgerBondClient.currentLog());
        }
    }
    // GRD_R4719_SpeedUpFormLetter_pkoz, pkoz, 24.11.2011 <--

    // </GEEU>
    for (more = rsL.first(tmpLedgerTrans);
         more;
         more = rsL.next(tmpLedgerTrans))
    {
        ledgerVoucherTransObject = LedgerVoucherTransObject::newCreateTrans(
                                           this,
                                           _ledgerPostingType,
                                           _ledgerAccount,
                                           _dimension,
                                           tmpLedgerTrans.CurrencyCode,
                                           -tmpLedgerTrans.AmountCur,
                                           _sourceTableId,
                                           _sourceRecId);

        ledgerVoucherTransObject.parmTransTxt(_transactionTxt.txt());
        _ledgerVoucher.addTrans(ledgerVoucherTransObject);
        // <GEEU>

        if (ledgerBondClient && tmpLedgerTrans.AmountCur)
        {

            // GRD_R4719_SpeedUpFormLetter_pkoz, pkoz, 24.11.2011 -->
            if (GRD5::isR4719_2())
            {
                if (!GRD_LoadedBondInfo)
                {
                    GRD_LoadedBondInfo = true;
                    if (ledgerBondClient)
                    {
                        logTable = ledgerBondClient.log2Table(ledgerBondClient.currentLog());
                    }
                }
            }
            // GRD_R4719_SpeedUpFormLetter_pkoz, pkoz, 24.11.2011 <--

            bondTransObject = ledgerBondClient.bondTransObject(ledgerBondClient.lastVrefId());
            while select logTable
                where logTable.CurrencyCode == tmpLedgerTrans.CurrencyCode   &&
                      logTable.Crediting    != bondTransObject.remainCrediting()
            {
                ledgerBondClient.bondVRef2VRef(bondTransObject.vrefId(), logTable.vRef);
                if (bondTransObject.remainAmountCur() == 0)
                {
                    break;
                    // </GEEU>
                }
            }
        // <GEEU>
        }
    }
}
// </GEEU>
т.е. если для конкретных строк нет проводок, то часть копирований не происходит, за счет чего тоже экономится прилично времени.

P.S.
Вообще, грустно, что обработка накладных совсем не оптимизировалась на обработку больших объемов информации.
За это сообщение автора поблагодарили: Wamr (10).