也许并行计算机可以用于此?这是一个说明这个想法的粗略设置:
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
]