Многопоточные процессы в Microsoft Dynamics AX

Зачастую на практике разработки в Dynamics AX бывают ситуации, когда необходима обработка большого объема данных, которая включает в себя выполнение “тяжелых” операций над однородными объектами. Например, отображение на форме актуальной суммы дебиторской задолженности по списку клиентов, периодическая операция расчета потребностей магазинов, обновление физического количества по номенклатурам в строках инвентаризации и т.п. Однако при этом всегда ставится задача, чтобы такая обработка не занимала много времени. Понятно, что при выполнении таких операций последовательно уйдёт очень много времени. На помощь приходит возможность запустить процессы, которые будут выполняться одновременно друг с другом.

Одним из способов запуска выполнения одной операции является реализация класса Thread. Рассмотрим его использование на примере метода TutorialThread.run().

static client Thread run(LabelType searchFor)
{
    Thread t = new Thread();
    ;

    t.setInputParm([searchFor]);
    t.run( classnum( TutorialThread ), staticmethodstr(TutorialThread,runThread));
    return t;

}

Объявляется экземпляр класса Tread. В качестве входных параметров (если они необходимы) указывается контейнер с ними. Для передачи на запуск потока вызывается метод run(), параметрами являются наименование класса и статический метод, созданный в нём. Далее посмотрим на сам метод TutorialThread.runThread():

static client void runThread(Thread t)
{
    container   retVal;
    LabelType   searchFor;
    Tutorial_ThreadWork  tutorialThreadWork = new Tutorial_ThreadWork();
    ;

    [searchFor] = t.getInputParm();
    print "Searching for labels " + searchFor;
    pause;
    retVal = tutorialThreadWork.doTheWork(t,searchFor);
    print "Found " + int2str( conlen(retVal) ) + " Labels";
    pause;
    t.setOutputParm(retVal);
}

Извлекаются входные параметры с помощью метода t.getInputParm(). Далее выполняется необходимая операция с данными. Если необходимо получить результат выполнения, то можно это сделать с помощью метода t.setOutputParm(). Результатом выполнения может быть контейнер с логической константой — так в дальнейшем можно будет понять, завершилась ли операция (если она ещё выполняется, то t.getOutputParm() будет возвращать пустой контейнер) и завершилась ли корректно.

Таким образом, создав сколько необходимо экземпляров класса, можно запустить столько же операций, которые будут выполняться независимо друг от друга.

Другим способом реализации многопоточных процессов является создание пакетных задач. Пример кода из метода RetailStatementPost_Multi.run():

public void run()
{
    //...

    // start processing for selected Stores.
    selectedStoreEnumerator = selectedStoreRecIds.getEnumerator();

    while (selectedStoreEnumerator.moveNext())
    {
        storeTable = RetailStoreTable::findRecId(selectedStoreEnumerator.current());

        // Create a RetailStatementPost task for each open statement belonging to the store.
        while select storeId, statementId from statementTable
            where   statementTable.storeId == storeTable.StoreNumber
        {
            soPoster = new RetailStatementPostSalesOrders();
            soPoster.parmStatementId(statementTable.statementId);

            if (this.isInBatch())
            {
                if (!batchHeader)
                {
                    batchHeader = BatchHeader::construct(this.parmCurrentBatch().BatchJobId);
                }

                this.batchInfo().parmCaption(strFmt("@RET260928", statementTable.statementId));
                soPoster.parmInBatch(true);
                soPoster.batchInfo().parmCaption(strfmt("@RET5022", storeTable.StoreNumber, statementTable.statementId));
                batchHeader.addRuntimeTask(soPoster, this.parmCurrentBatch().RecId);
            }
            else
            {
                soPoster.run();

                //...
            }
        }

        if (batchHeader)
        {
            batchHeader.save();
        }
    }

    //...
}

Каждый новый экземпляр класса RetailStatementPostSalesOrders – одна задача. Сколько под эти задачи создать потоков решает пакетный сервер (или серверы) на основе своих настроек и загрузки другими пакетными заданиями. Пакетным заданиям назначается пакетная группа, которую по умолчанию наследуют пакетные задачи, создаваемые в runtime. Также пакетные группы назначаются для обработки пакетным серверам. Исходя из этого, число потоков для выполнения задач определенной пакетной группы ограничено сверху тем, скольким пакетным серверам эта группа назначена для обработки и какое число потоков настроено для каждого из этих серверов.

Comments

So empty here ... leave a comment!

Добавить комментарий

Sidebar