А не вернуться ли нам к теме многопоточности?
Насколько я знаю, есть как минимум два типа многопоточности:
Кооперативная. Реально в системе есть только один поток выполнения. Многопоточность эмулируется квазипотоками. Переключение между квазипотоками происходит по воле каждого из них: при помощи вызова специальной функции или при любом обращении к системе. Такая система многопоточности в Win 3.11. Такую систему наиболее реально построить для модулей 1С. Ведь 1С не рассчитана на многопоточность. А кооперативная многопоточность использует только один поток выполнения, поэтому не происходит одновременного обращения к общим данных из разных потоков. Идеальная многопоточность для 1С выглядела бы, наверное, так:
Перем гШедулер;
Процедура Обработка ()
гШедулер = СоздатьОбъект ("Шедулер");
гШедулер.ЗарегистрироватьМодуль ();
Для Ч = 1 По 10000 Цикл
... какая-то обработка...
гШедулер.ОтдатьУправление ();
КонецЦикла;
КонецПроцедуры
В шедулере регистрируются модули. Во время выполнения модуль, получивший управление, делают некую часть своей работы и вызывает ОтдатьУправление (). Шедулер смотрит, есть ли еще модули, и отдает управление следующему в очереди. Если других модулей нет, то управление получает первый.
Не уверен, что такой способ сделать реально. Я просто не знаю деталей. Может быть, кто-то знает лучше?
Если нельзя получить "идеальный" способ выполнения, то наверняка можно пойти более реальным путем. Например, так:
Перем гШедулер;
Процедура Выполнить ()
гШедулер = СоздатьОбъект ("Шедулер");
гШедулер.ЗарегистрироватьМодуль ("Обработка");
гШедулер.Старт ();
КонецПроцедуры
Функция Обработка ()
... некая обработка...
Если РаботаОкончена Тогда
Возврат 0;
Иначе
Возврат 1;
КонецЕсли;
КонецФункции
В этом случае берем, например, тело цикла обхода результата запроса и выносим его в отдельную функцию. Т.е. чтобы один вызов этой функции соответствовал выполнению одной итерации цикла. В шедулере региструется несколько модулей с несколькими подобными функциями. Шедулер по методу "Старт" тупо последовательно вызывает все зарегистрированные функции. Если какая-то функция возвращает 0, то эта функция исключается из цикла выполнения.
В принципе, такую многозадачность можно сделать и штатными методами. Однако отдельный шедулер дает следующие выгоды:
- Модулям не обязательно знать друг о друге. Если использовать только штатные методы, то модули, скорее всего, будут "завязаны" друг на друга, что плохо влияет на модульность.
- Шедулер может при "переключении контекстов" заставить 1С обработать поступившие оконные сообщения. Что дает возможность использовать кнопки и другие элементы диалога 1С. Это, например, даст возможность прервать выполнение обработки цивилизованным методом - по кнопке "Отмена", а не по Esc. Также у пользователя появится возможность влиять на выполнение обработки в процессе выполнения.
В общем-то, подобная кооперативная многозадачность мало, что дает полезного
В основном это большая интерактивность системы, возможности многопроцессорной обработки никак не используются. Хотя кому как
Да! В принципе, шедулер частично может быть реализован в виде специального класса 1С++.
Вытесняющая В этом случае у нас уже есть "настоящие" потоки. Каждый поток выполняется так, как будто он один в системе. Переключение между потоками производит система, причем в любой момент, а не так, как в кооперативном варианте - когда хочет сам поток. Здесь у нас возможен одновременный доступ к общим данным разных потоков. Со всеми вытекающими проблемами. 1С никак не рассчитана многопоточное выполнение, поэтому реализация параллельного выполнения модулей на языке 1С вряд ли возможно.
Однако, использование многопоточности возможно для ВК. 1С собрана, насколько я понимаю, с использованием многопоточной CRT. Следовательно операции выделения/освобождения памяти могут выполняться конкурентно из разных потоков, без опасения испортить хип. Если это не так, то, в принципе, можно перейти в ВК на отдельный хип, не зависимый от 1С.
В качестве возможного применения многопоточности можно посмотреть на индексированную таблицу. Например, можно получить данные и в отдельном потоке запустить группировку/сортировку/индексирование. В основном потоке в этот момент можно вытаскивать какие-то данные из БД или выводить что-то в отчет.
Еще применение. Получение данных от MSSQL работает довольно хитрым образом. На клиент уходят только реально запрошенные данные. Я еще как-то удивлялся, когда запустил запрос, который должен был практически вернуть содержимое таблицы в гигабайт весом. Этот запрос выполнился практически мгновенно. И только когда дело дошло до выборки результата наступили долгожданные тормоза
Так вот. Выборку порций данных можно поместить в отдельный поток выполнения. А в основном потоке можно выводить уже полученную порцию в отчет.
Основной вопрос в случае с индексированной таблицей: использование CValue. Там CValue используется очень активно. Я просто не знаю, не происходит ли при обработке CValue обращений к каким-нибудь общим данным? Если не происходит, то переделок может потребовать очень мало. В основном это блокировка при доступе к данным ИТ в момент, когда обработка в другом потоке еще не завершилась. В этом случае можно использовать какой-то объект синхронизации, чтобы при обращении из основного потока основной поток останавливался и ждал завершения второго потока.