这个问题来自最近的问题“Correct way to cap Mathematica memory use?”
我想知道,是否有可能以编程方式重新启动MathKernel,使当前的FrontEnd进程连接到新的MathKernel进程并在新的MathKernel会话中评估一些代码?我的意思是“透明”重启,它允许用户继续使用FrontEnd,同时拥有新的MathKernel流程,其中一些代码来自之前评估/评估的内核?
问题的动机是有一种方法可以自动重启MathKernel,因为它需要太多的内存而不会破坏计算。换句话说,计算应该在新的MathKernel过程中自动继续,而不与用户交互(但保持用户与最初的 Mathematica 交互的能力)。在新内核中应该评估什么代码的细节当然是针对每个计算任务的。我正在寻找一个通用的解决方案,如何自动继续计算。
答案 0 :(得分:7)
昨天从comment by Arnoud Buzing开始,在Stack Exchange Mathematica聊天中,完全引用:
在笔记本中,如果您有多个单元格,可以单独将Quit放入单元格中并设置此选项:
SetOptions[$FrontEnd, "ClearEvaluationQueueOnKernelQuit" -> False]
然后,如果你上面和下面有一个单元格,并选择全部三个并进行评估,内核将退出,但前端评估队列将继续(并重新启动最后一个单元格的内核)。
- Arnoud Buzing
答案 1 :(得分:5)
以下方法运行一个内核来打开具有自己内核的前端,然后关闭并重新打开,更新第二个内核。
此文件是MathKernel输入,C:\ Temp \ test4.m
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.bat
@echo off
setlocal
PATH = C:\Program Files\Wolfram Research\Mathematica\8.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
设置起来有点精心设计,目前的形式取决于知道在关闭和重启第二个内核之前需要等待多长时间。
答案 2 :(得分:4)
也许可以使用并行计算机器吗?这是一个粗略的设置,说明了这个想法:
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
]
这是一个过于精细的设置,可生成1,000个三元组的列表。 getTheJobDone
运行一个循环,该循环一直持续到结果列表包含所需数量的元素。循环的每次迭代都在子内核中进行评估。如果子内核评估失败,则重新启动子内核。否则,其返回值将添加到结果列表中。
要试一试,请评估:
getTheJobDone[]
要演示恢复机制,请打开 Parallel Kernel Status 窗口并不时终止子内核。只要子内核死亡,getTheJobDone
就会感受到疼痛并打印 Ouch!。但是,整个工作仍在继续,并返回最终结果。
这里的错误处理非常粗糙,可能需要在实际应用程序中加以支持。另外,我还没有调查子内核中真正严重的错误情况(如耗尽内存)是否会对主内核产生负面影响。如果是这样,那么如果MemoryInUse[]
超过预定的阈值,那么子内核可能会自杀。
更新 - 隔离主内核与子内核崩溃
在玩这个框架时,我发现在主内核和子内核之间使用共享变量会导致Mathematica在子内核崩溃时不稳定。这包括使用上面显示的DistributeDefinitions[resultSoFar]
,以及使用SetSharedVariable
的显式共享变量。
要解决此问题,我通过文件传输了resultSoFar
。这消除了两个内核之间的同步,最终结果是主内核仍然没有意识到子内核崩溃。它还具有在主内核崩溃时保留中间结果的良好副作用。当然,它也使得子内核调用相当慢。但是,如果每次调用子内核都会执行大量工作,那么这可能不是问题。
以下是修订后的定义:
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
]
答案 3 :(得分:3)
当我为一个长循环运行CUDAFunction并且CUDALink内存不足时,我有类似的要求(类似于:https://mathematica.stackexchange.com/questions/31412/cudalink-ran-out-of-available-memory)。即使使用最新的Mathematica 10.4版本,内存泄漏也没有任何改善。我在这里找到了一个解决方法,希望你能发现它有用。我们的想法是使用bash脚本通过从bash脚本传递参数多次调用Mathematica程序(以批处理模式运行)。这是详细说明和演示(这是针对Window OS):
以下是test.m文件的演示
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代码从命令行读取参数并将其用于计算。 以下是使用不同参数多次运行test.m的bash脚本(script.sh)。
#c:\cygwin64\bin\bash
for ((i=2;i<10;i+=2))
do
math -script test.m -start $i
done
在cygwin终端类型&#34; chmod a + x script.sh&#34;要启用该脚本,您可以通过键入&#34; ./ script.sh&#34;来运行它。
答案 4 :(得分:2)
您可以使用Exit[]
以编程方式终止内核。当您下次尝试评估表达式时,前端(笔记本)将自动启动新内核。
保留“来自先前内核的某些代码”将变得更加困难。你必须决定你想要保留什么。如果您认为要保留所有内容,那么重新启动内核就没有意义了。如果您知道要保存的定义,可以在终止内核之前使用DumpSave
将它们写入文件,然后使用<<
将该文件加载到新内核中。
另一方面,如果您知道哪些定义占用了太多内存,则可以使用Unset
,Clear
,ClearAll
或Remove
删除这些内容定义。您还可以将$ HistoryLength设置为小于Infinity
(默认值)的值,如果这是您的记忆所在。
答案 5 :(得分:0)
听起来像是CleanSlate的工作。
<< Utilities`CleanSlate`;
CleanSlate[]
来自:http://library.wolfram.com/infocenter/TechNotes/4718/
“CleanSlate,尝试尽一切可能将内核恢复到最初加载CleanSlate.m包时的状态。”