Рекурсивный вызов дублированного скрипта Bash, делающий невозможным доступ к ресурсам
Изменить: Этот пост теперь рассматривается по-новому, так как проблема должна быть представлена немного по-другому. Это здесь: Как я могу эффективно выполнять преобразования XSLT для большого количества файлов параллельно?
Я застрял в попытках распараллелить процесс, и после некоторого времени, потраченного на него, я хотел бы попросить некоторую помощь...
По сути, у меня есть много XML-файлов для преобразования с использованием определенного листа XSLT. Но лист использует вызов (очень медленного) API для извлечения дополнительных данных, и взятие всего пакета XML за один раз займет (очень) много времени.
Поэтому я разбил все файлы из исходной "входной" папки в подпапку, содержащую примерно 5000 файлов XML, и также скопировал следующий скрипт Bash в каждую подпапку:
for f in *.xml
do
java -jar ../../saxon9he.jar -xsl:../../some-xslt-sheet.xsl -s:$f
done
И я вызываю каждый процесс, для каждой папки, из "корневой" папки, содержащей вместе "входную" папку, библиотеку Saxon и лист XSLT:
find input -type d -exec sh {}/script.sh \;
Но я получаю эту ошибку:
Unable to access jarfile ../../saxon9he.jar
Я предполагаю, что это происходит из-за того, что я работаю из "корневой" папки, когда вызываемые скрипты находятся ниже в каталогах. Я мог бы решить проблему (если я прав), скопировав все ресурсы в каждой подпапке, но я нашел решение, делающее мой текущий подход еще более неуклюжим.
Спасибо всем, кто мог бы иметь идею и заставить меня понять это!
2 ответа
Во-первых, вы действительно не хотите инициализировать новую виртуальную машину Java для запуска каждого преобразования: обычно это занимает гораздо больше времени, чем выполнение самого преобразования. Чтобы представить это в перспективе, для "типичных" преобразований вы часто будете видеть время инициализации Java 3 секунды, время компиляции таблицы стилей 300 мс, время преобразования 10 мс. Так что, если вы можете найти способ сделать это, только инициализируя Java и скомпилировав таблицу стилей один раз, ваше общее время для документов 10K будет 2 минуты, а не 10 часов.
Существуют различные способы достижения этого, но все они включают использование чего-то другого, кроме сценария оболочки, для управления процессом. Самым простым, на мой взгляд, является управление им из самого XSLT с помощью функции collection() для доступа ко всем файлам в каталоге. Это дает дополнительный бонус, если вы используете Saxon-EE, что файлы будут обрабатываться (анализироваться) параллельно с использованием всех ядер на вашей машине, что может ускорить процесс еще в 4 раза или около того. Вам просто нужно добавить точку входа в таблицу стилей примерно так:
<xsl:template name="main">
<xsl:for-each select="collection('file:///my/dir?select=*.xml;recurse=yes')!saxon:discard-document(.)">
<xsl:result-document href="....">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
Вызов saxon:discard-document является необязательным, но поскольку он делает документы пригодными для сбора мусора, это означает, что у вас меньше шансов исчерпать память.
Другой подход к написанию цикла управления заключается в использовании специализированной оболочки, такой как xmlsh.
Попробуйте сделать так, чтобы ввести каталог для каждого аргумента и вызвать скрипт в нем:
for d in */script.sh
do
(
cd "$(basename "$d")"
sh ./script.sh
)
done