Само перезапуск MathKernel-возможно ли это в Mathematica?
этот вопрос исходит из недавнего вопроса" правильный способ cap Mathematica использование памяти?"
интересно, можно ли программно перезапустить MathKernel, сохраняя текущий процесс интерфейса, подключенный к новому процессу MathKernel и оценивая некоторый код в новом сеансе MathKernel? Я имею в виду "прозрачный" перезапуск, который позволяет пользователю продолжать работать с интерфейсом, имея новый свежий процесс MathKernel с некоторым кодом из предыдущее ядро оценивалось / оценивалось в нем?
мотивация вопроса состоит в том, чтобы иметь способ автоматизировать перезапуск MathKernel, когда он занимает слишком много памяти не нарушая вычисления. Другими словами, вычисление должно быть автоматически продолжено в новом процессе MathKernel без взаимодействия с пользователем (но сохраняя возможность для пользователя взаимодействовать с Mathematica как было изначально). Подробности о том, какой код должен быть оцененные в новом ядре, конечно, специфичны для каждой вычислительной задачи. Я ищу общее решение, как автоматически продолжить вычисления.
6 ответов
С комментарий Buzing Арнуд вчера, на Stack Exchange Mathematica чат, цитируя полностью:
в записной книжке, если у вас есть несколько ячеек, вы можете поместить Quit в ячейку и установить эту опцию:
SetOptions[$FrontEnd, "ClearEvaluationQueueOnKernelQuit" -> False]
затем, если у вас есть ячейка выше и ниже нее и выберите все три и оцените, ядро выйдет, но очередь оценки интерфейса будет продолжаться (и перезапустите ядро для последней ячейки).
-- Arnoud Buzing
следующий подход запускает одно ядро, чтобы открыть интерфейс со своим собственным ядром, которое затем закрывается и снова открывается, обновляя второе ядро.
этот файл является входом MathKernel, C:\Temp\test4 - ... м
Needs["JLink`"];
$FrontEndLaunchCommand="Mathematica.exe";
UseFrontEnd[
nb = NotebookOpen["C:\Temp\run.nb"];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb];
];
Pause[8];
CloseFrontEnd[];
Pause[1];
UseFrontEnd[
nb = NotebookOpen["C:\Temp\run.nb"];
Do[SelectionMove[nb, Next, Cell],{12}];
SelectionEvaluate[nb];
];
Pause[8];
CloseFrontEnd[];
Print["Completed"]
демо ноутбука, C:\Temp\run.nb содержит две ячейки:
x1 = 0;
Module[{},
While[x1 < 1000000,
If[Mod[x1, 100000] == 0, Print["x1=" <> ToString[x1]]]; x1++];
NotebookSave[EvaluationNotebook[]];
NotebookClose[EvaluationNotebook[]]]
Print[x1]
x1 = 0;
Module[{},
While[x1 < 1000000,
If[Mod[x1, 100000] == 0, Print["x1=" <> ToString[x1]]]; x1++];
NotebookSave[EvaluationNotebook[]];
NotebookClose[EvaluationNotebook[]]]
начальное ядро открывает интерфейс и запускает первую ячейку, затем оно выходит из интерфейса, снова открывает его и запускает вторую ячейку.
все может быть запустите либо вставкой (за один раз) ввода MathKernel в сеанс ядра, либо его можно запустить из пакетного файла, например C:\Temp\RunTest2 - ... летучая мышь!--4-->
@echo off
setlocal
PATH = C:\Program Files\Wolfram Research\Mathematica.0\;%PATH%
echo Launching MathKernel %TIME%
start MathKernel -noprompt -initfile "C:\Temp\test4.m"
ping localhost -n 30 > nul
echo Terminating MathKernel %TIME%
taskkill /F /FI "IMAGENAME eq MathKernel.exe" > nul
endlocal
это немного сложно настроить, и в его текущей форме это зависит от того, как долго ждать, прежде чем закрыть и перезапустить второе ядро.
возможно, для этого можно использовать механизм параллельных вычислений? Вот грубая установка, которая иллюстрирует эту идею:
Needs["SubKernels`LocalKernels`"]
doSomeWork[input_] := {$KernelID, Length[input], RandomReal[]}
getTheJobDone[] :=
Module[{subkernel, initsub, resultSoFar = {}}
, initsub[] :=
( subkernel = LaunchKernels[LocalMachine[1]]
; DistributeDefinitions["Global`"]
)
; initsub[]
; While[Length[resultSoFar] < 1000
, DistributeDefinitions[resultSoFar]
; Quiet[ParallelEvaluate[doSomeWork[resultSoFar], subkernel]] /.
{ $Failed :> (Print@"Ouch!"; initsub[])
, r_ :> AppendTo[resultSoFar, r]
}
]
; CloseKernels[subkernel]
; resultSoFar
]
это слишком сложная настройка для создания списка из 1000 тройных чисел. getTheJobDone
запускает цикл, который продолжается до тех пор, пока список результатов не содержит нужное количество элементов. Каждая итерация цикла оценивается в подкернеле. Если оценка subkernel не удается, subkernel возобновлен. В противном случае его возвращаемое значение добавляется к полученный список.
чтобы попробовать это, оцените:
getTheJobDone[]
чтобы продемонстрировать механизм восстановления, откройте Состояние Параллельного Ядра окно и убить subkernel время от времени. getTheJobDone
будет чувствовать боль и печатать Оуч! всякий раз, когда subkernel умирает. Тем не менее, общая работа продолжается, и конечный результат возвращается.
обработка ошибок здесь очень грубая и, вероятно, должна быть поддержана в реальном приложение. Кроме того, я не исследовал, будут ли действительно серьезные условия ошибок в подкернелях (например, нехватка памяти) оказывать неблагоприятное влияние на основное ядро. Если так, то, возможно, субкернелы могут покончить с собой, если ... --5--> превысил заданный порог.
Update-изоляция основного ядра от сбоев Subkernel
играя с этой базы, я обнаружил, что любое использование общих переменных между основными ядро и подкернель сделали Mathematica неустойчивой в случае сбоя подкернеля. Это включает в себя использование DistributeDefinitions[resultSoFar]
как показано выше, а также явные общие переменные с использованием SetSharedVariable
.
чтобы обойти эту проблему, я передал resultSoFar
через файл. Это устранило синхронизацию между двумя ядрами, в результате чего основное ядро оставалось в блаженном неведении о неполадке. Он также имел славный побочный эффект сохранять промежуточные результаты внутри в случае аварии основного ядра. Конечно, это также делает вызовы subkernel довольно медленными. Но это не может быть проблемой, если каждый вызов subkernel выполняет значительный объем работы.
вот пересмотренные определения:
Needs["SubKernels`LocalKernels`"]
doSomeWork[] := {$KernelID, Length[Get[$resultFile]], RandomReal[]}
$resultFile = "/some/place/results.dat";
getTheJobDone[] :=
Module[{subkernel, initsub, resultSoFar = {}}
, initsub[] :=
( subkernel = LaunchKernels[LocalMachine[1]]
; DistributeDefinitions["Global`"]
)
; initsub[]
; While[Length[resultSoFar] < 1000
, Put[resultSoFar, $resultFile]
; Quiet[ParallelEvaluate[doSomeWork[], subkernel]] /.
{ $Failed :> (Print@"Ouch!"; CloseKernels[subkernel]; initsub[])
, r_ :> AppendTo[resultSoFar, r]
}
]
; CloseKernels[subkernel]
; resultSoFar
]
у меня есть аналогичное требование, когда я запускаю CUDAFunction для длинного цикла, и CUDALink исчерпал память (аналогично здесь: https://mathematica.stackexchange.com/questions/31412/cudalink-ran-out-of-available-memory) - ... Нет никаких улучшений в утечке памяти даже с последней версией Mathematica 10.4. Я придумываю обходной путь и надеюсь, что вы найдете его полезным. Идея заключается в том, что вы используете скрипт bash для вызова программы Mathematica (запуск в пакетном режиме) несколько раз с передачей параметров из скрипта bash. Вот подробная инструкция и демо (это для Window OS):
- для использования bash-скрипта в Win_OS необходимо установить cygwin (https://cygwin.com/install.html).
- преобразуйте свой ноутбук mathematica в пакет (.m) возможность использования в режиме скрипта. Если вы сохраните свой ноутбук с помощью " Сохранить как.."вся команда будет преобразована в комментарии (это было отмечено Wolfram Research), поэтому лучше, чтобы вы создаете пакет (File->New-Package), затем копируете и вставляете в него свои команды.
- напишите сценарий bash с помощью редактора Vi (вместо блокнота или gedit для окна), чтобы избежать проблемы "\r" (http://www.linuxquestions.org/questions/programming-9/shell-scripts-in-windows-cygwin-607659/).
вот демонстрация теста.файл м
str=$CommandLine;
len=Length[str];
Do[
If[str[[i]]=="-start",
start=ToExpression[str[[i+1]]];
Pause[start];
Print["Done in ",start," second"];
];
,{i,2,len-1}];
этот код mathematica считывает параметр из командной строки и использует его для расчет. Вот сценарий bash (script.sh) запустить тест.m много раз с разными параметрами.
#c:\cygwin64\bin\bash
for ((i=2;i<10;i+=2))
do
math -script test.m -start $i
done
в типе терминала cygwin "chmod a+x script.sh" чтобы включить скрипт, вы можете запустить его, набрав". /script.sh".
вы можете программно завершить работу ядра с помощью Exit[]
. Передняя часть (ноутбук) автоматически запустит новое ядро при следующей попытке оценить выражение.
сохранение "некоторого кода из предыдущего ядра" будет сложнее. Вы должны решить, что вы хотите сохранить. Если вы думаете, что хотите сохранить все, то нет смысла перезапускать ядро. Если вы знаете, какие определения вы хотите сохранить, вы можете использовать DumpSave
написать их в файл перед завершением ядра, а затем использовать <<
загрузить этот файл в новое ядро.
С другой стороны, если вы знаете, что определений занимают слишком много памяти, вы можете использовать Unset
, Clear
, ClearAll
или Remove
чтобы удалить эти определения. Вы также можете установить $HistoryLength на что-то меньшее, чем Infinity
(по умолчанию), если это то, куда идет ваша память.
звучит как работа для CleanSlate.
<< Utilities`CleanSlate`;
CleanSlate[]
From:http://library.wolfram.com/infocenter/TechNotes/4718/
" CleanSlate, пытается сделать все возможное, чтобы вернуть ядро в состояние, в котором оно было, когда CleanSlate.первоначально был загружен пакет m."