12

这个问题来自最近的问题“正确的方法来限制Mathematica内存使用?

我想知道,是否可以以编程方式重新启动 MathKernel,以保持当前 FrontEnd 进程连接到新的 MathKernel 进程并在新的 MathKernel 会话中评估一些代码?我的意思是“透明”重启,它允许用户继续使用 FrontEnd,同时拥有新的全新 MathKernel 进程,其中包含来自先前内核的一些代码进行评估/评估?

这个问题的动机是有一种方法可以在 MathKernel 占用太多内存时自动重新启动,而不会破坏计算。换句话说,计算应该在新的 MathKernel 进程中自动继续,无需与用户交互(但保持用户与Mathematica交互的能力与原来一样)。关于应该在新内核中评估哪些代码的细节当然是针对每个计算任务的。我正在寻找如何自动继续计算的通用解决方案。

4

6 回答 6

9

来自Arnoud Buzing昨天在 Stack Exchange Mathematica 聊天中的评论,完全引用:

在笔记本中,如果您有多个单元格,您可以将 Quit 单独放在一个单元格中并设置此选项:

SetOptions[$FrontEnd, "ClearEvaluationQueueOnKernelQuit" -> False]

然后,如果您在其上方和下方都有一个单元格并选择所有三个并评估,内核将退出但前端评估队列将继续(并为最后一个单元重新启动内核)。

——阿诺德·布津

于 2012-12-06T09:29:39.577 回答
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

设置起来有点复杂,在目前的形式下,它取决于知道在关闭和重新启动第二个内核之前要等待多长时间。

于 2011-10-23T12:12:28.980 回答
5

也许并行计算机可以用于此?这是一个说明这个想法的粗略设置:

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会感到疼痛并打印哎哟!每当子内核死亡时。但是,整个作业会继续并返回最终结果。

这里的错误处理非常粗糙,可能需要在实际应用程序中得到支持。此外,我还没有调查子内核中真正严重的错误情况(如内存不足)是否会对主内核产生不利影响。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
  ]
于 2011-10-29T06:12:28.757 回答
3

当我为长循环运行 CUDAFunction 并且 CUDALink 内存不足时,我有类似的要求(此处类似:https ://mathematica.stackexchange.com/questions/31412/cudalink-ran-out-of-available-memory ) . 即使使用最新的 Mathematica 10.4 版本,内存泄漏也没有改善。我在这里找到了一个解决方法,希望你会发现它很有用。这个想法是您使用 bash 脚本多次调用 Mathematica 程序(以批处理模式运行),并从 bash 脚本传递参数。这是详细说明和演示(这是针对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 终端中键入“chmod a+x script.sh”以启用脚本,然后您可以通过键入“./script.sh”来运行它。

于 2016-03-10T16:52:37.800 回答
2

您可以使用 以编程方式终止内核Exit[]。当您下次尝试评估表达式时,前端(笔记本电脑)将自动启动一个新内核。

保留“来自以前内核的一些代码”将更加困难。您必须决定要保留什么。如果您认为要保留所有内容,那么重新启动内核是没有意义的。如果您知道要保存哪些定义,则可以DumpSave在终止内核之前将它们写入文件,然后<<将该文件加载到新内核中。

另一方面,如果您知道哪些定义占用了太多内存,则可以使用UnsetClearClearAllRemove删除这些定义。Infinity如果您的内存在哪里,您还可以将 $HistoryLength 设置为小于(默认值)的值。

于 2011-10-23T06:29:59.513 回答
0

听起来像是 CleanSlate 的工作。

<< Utilities`CleanSlate`;
CleanSlate[]

来自: http: //library.wolfram.com/infocenter/TechNotes/4718/

“CleanSlate,尽一切可能将内核返回到最初加载 CleanSlate.m 包时的状态。”

于 2011-10-23T09:45:29.447 回答