Difference between revisions of "Mutex.InterProcessExecuteFunction"

From SunFlurry wiki
Jump to: navigation, search
1>Admin
m (1 revision imported)
 
(No difference)

Latest revision as of 11:38, 18 November 2022

  InterProcessExecuteFunction (Работа с подчиненными процессами)
Объект:Семафор
Статус разработки: Реализована
Тип:Функция
Обращение к БД:Нет
Исключения:Невозможно превратить в строку, системная ошибка
Визуальность:Нет

Функция вызывает исполнение указанной функции в подчиненном процессе, созданном ранее функцией InitializeSeparateProcess, и возвращает ошибку или результат ее исполнения. При вызове в функцию разрешено передавать объекты произвольного вида, изменяемые аргументы-переменные также могут быть обновлены после исполнения.

Функции, выполняющиеся в отдельных процессах, могут использоваться для изолирования кода исполнения, к примеру, когда внешняя библиотека (или OLE объект) работают со сбоями и могут испортить системную память, тем самым вызывая завершение с ошибкой всего процесса клиента. После инициализации, процесс будет находиться в режиме ожидания исполнения, клиент же может периодически вызывать функцию InterProcessExecuteFunction для исполнения программы в ожидающем процессе. После удаления объекта семафора из системы, подчиненный процесс также будет завершен. Исполнение всегда происходит в синхронном режиме (функция ожидает окончания исполнения удаленной функции и только после этого возвращает результат), асинхронный режим для большей гибкости при работе планируется в будущем.

При работе с вызовами функций в подчиненных процессах необходимо знать:

  • Все аргументы копируются в подчиненный процесс с помощью экспорта и импорта, поэтому, они не будут связаны с оригинальными переменными и объектами (подчиненный процесс имеет собственное адресное пространство в памяти). В виде аргументов позволяется использовать все простые и сложные типы (строки, числа, даты, объекты базы данных, списки, таблицы, электронные таблицы), однако:
    • Большие по объему аргументы (к примеру, электронные таблицы) могут замедлить исполнение функций, из-за затрат времени на экспорт/импорт. Рекомендуется использовать простые аргументы или легкие списки и таблицы.
    • Электронные таблицы, таблицы, списки, связанные с формой, в подчиненном процессе больше не будут с ней связаны. Таблицы, адресующие строчные части объектов базы данных, больше не будут их адресовать.
    • Все изменения в сложных объектах (списках, таблицах) не будут отражаться на оригинальных таблицах в основном процессе. Если список передается, как аргумент-переменная с пометкой ByRef, после выполнения функции, оригинальный список в переменной будет заменен копией из подчиненного процесса, со всеми возможными изменениями.
    • Передача объектов форм не имеет смысла, так как подчиненный поток всегда работает в консольном режиме.
    • Объекты типа ini, memoryrecord, file, picture, ip, ole, dbf, lib, exdb, xml, query, tempdb и др. не передаются в подчиненные процессы. Если необходимо, к примеру, передать картинку, необходимо сначала экспортировать ее в строку.
    • Локальные переменные модуля, в котором находится исполняемая функция, не будут доступны при исполнении. Используйте переменные глобальных модулей.
    • Все передаваемые объекты базы данных будут перенесены на сторону подчиненного процесса незагруженными, для работы с ними системе придется снова загрузить их из базы данных, что может занять дополнительное время. Измененные и новые несохраненные объекты не имеет смысла передавать в подчиненные процессы, все изменения будут утеряны.
  • Скорость исполнения функций с простыми аргументами достаточно высока (не сильно уступает прямому исполнению, см. ниже). Однако вызов InitializeSeparateProcess может занимать достаточно долгое время, поэтому, выгодно, однажды инициализировав, использовать подчиненный процесс многократно. Кроме того, при передаче объемных аргументов (большие таблицы или списки, длинные строки) исполнение также может замедляться из-за времени экспорта-импорта.
  • Для увеличения скорости исполнения выгоднее использовать функции, которые выполняют большую, более длительную работу, по сравнению с функциями, которые завершаются очень быстро.
  • Некоторые визуальные функции и функции диалога, типа Message, Box, AskQuestion поддерживаются (окно будет выведено на экране, вызывавшей стороны, после ответа пользователя, если он подразумевается, результат будет передан на удаленную сторону). Если функция не поддерживается, она будет вести себя так, как будто пользователь нажал на отмену. В будущем могут быть поддержаны функции, которые ранее не поддерживались.
  • Удаленная сторона может использовать некоторые функции для взаимодействия с локальной стороной (к примеру, функцию InterProcessServerTimeout).

Синтаксис

Mutex.InterProcessExecuteFunction(<Имя функции (STRING)>,<Аргумент 1>,<Аргумент 2>...):<Результат исполнения функции>

Аргументы

  • <Имя функции (STRING)> - Аргумент задает имя функции локального модуля, переданного процессу в момент его инициализации или глобального модуля. Если функция не найдена, будет вызвано исключение.
  • <Аргумент ?> - (возможен аргумент-переменная (ByRef)) (необязательный аргумент) Аргументы, передаваемые исполняемой функции. Аргументы с типом ByRef будут скопированы назад после окончания исполнения, если функция не вызвала исключения.

Возвращаемое значение

Возвращает результат исполнения функции в подчиненном процессе, если при исполнении, функция не вызвала исключения.

Примеры

//Пример оценивает разницу в скорости прямого исполнения и исполнения функции в подчиненном приложении с простыми и сложными аргументами

  Function Сложение(Переменная,Переменная2)
    Result:=Переменная+Переменная2;
  EndFunction

  Function ВозвратитьСписок(ДлинныйСписок)
    Result:=ДлинныйСписок;
  EndFunction

//Заполним длинный список вещественными аргументами
ДлинныйСписок:=List.Create();
For i:=1 To 10000 Do
  ДлинныйСписок.Add(i/3);
EndDo;


ProfilerClear();
ProfilerStart();
аПроцесс:=Mutex.InitializeSeparateProcess();

//10000 вызовов простой функции
For i:=1 To 10000 Do
  Сложение(i,i);
  аПроцесс.InterProcessExecuteFunction("Сложение",i,i);
EndDo;

//100 вызовов функции с длинными аргументом
For i:=1 To 100 Do
  ДлинныйСписок:=ВозвратитьСписок(ДлинныйСписок);
  ДлинныйСписок:=аПроцесс.InterProcessExecuteFunction("ВозвратитьСписок",ДлинныйСписок);
EndDo;

ProfilerStop();
debugbreak;

Message("Done!");
//Для i7, конечные результаты исполнения каждого блока:
//Сложение(i,i)                                           -- 27.63 мс. (10000)
//аПроцесс.InterProcessExecuteFunction("Сложение",i,i)    -- 575.74 мс. (10000)
//ДлинныйСписок:=ВозвратитьСписок(ДлинныйСписок)          -- 0.418 мс. (100)
//ДлинныйСписок:=аПроцесс.InterProcessExecuteFunction...  -- 4.00 с. (100)
//Выводы:
//Потеря времени, при вызовах простых функций на коммуникации между процессами может составлять около (575.74-27.63)/10000 мс., т.е., около 54 микросекунд. 
//Такая потеря на практике не будет сказываться на скорости исполнения, даже если функция очень короткая и выполняется очень быстро. 
//Для медленных же функций, уменьшением в скорости исполнения можно пренебречь.
//Использование объемных аргументов (список из 10000 вещественных чисел экспортируется достаточно долгое время, в данном случае, он должен быть и экспортирован и импортирован, 
//  так как функция возвращает его в результате исполнения) будет очень сильно замедлять исполнение. В этом случае потеря времени может составлять 
//  (4000-0.418)/100 около 40 миллисекунд (примерно в 1000 раз больше, чем в первом случае), для часто исполняемых функций, такую задержку уже необходимо учитывать.