Mathematica 中的异步计算

发布于 2024-12-21 19:09:49 字数 1592 浏览 2 评论 0 原文

有时,当我在 Mathematica 中编写实验代码时,我会担心是否应该对其进行评估,因为它最终可能会让我的系统崩溃。

作为一个人为的示例,如果您尝试在 64 位计算机上运行以下代码片段,它很可能会导致您的系统在耗尽所有内存后完全停止运行。

junk = Table[{x, x}, {10^9}]; (* nom nom nom memory. Please don't run this. *)

当然,您可以将 MemoryConstrained 扔到它上面并希望得到最好的结果,但有时您不希望它阻止任何进一步的输入。为此,我认为实现中间立场的最佳方法是在单独的内核中执行评估。

这非常容易做到:

ClearAll[GetAvailableKernel];
GetAvailableKernel[] := Block[{i, kernels},
  kernels = Kernels[];
  If[Length@kernels !=  0,
   For[i = 1, i <= Length@kernels, i++,
    If[kernels[[i, 1, 2]] > 0, Return@kernels[[i]]]
    ]
   ];
  LaunchKernels[1]]

ClearAll[SafeEvaluate];
SetAttributes[SafeEvaluate, HoldFirst];
Options[SafeEvaluate] = {"EvaluationKernel" -> Null, 
   "ConstrainMemory" -> True, "MaxMemory" -> 2 1024^3};

SafeEvaluate[expr_, OptionsPattern[]] := Block[{evalkernel, result},
  If[OptionValue["EvaluationKernel"] != Null,
   evalkernel = OptionValue["EvaluationKernel"],
   evalkernel = GetAvailableKernel[]
   ];

  result  = If[OptionValue["ConstrainMemory"],
    With[{memory = OptionValue["MaxMemory"]},
     ParallelEvaluate[MemoryConstrained[expr, memory], evalkernel]],
    ParallelEvaluate[expr, evalkernel]];
  result]

然后您可以继续执行以下操作:

SafeEvaluate[Table[{x, x}, {1024^3}]]

Mathematica 会优雅地返回 $Aborted 告诉您内存不足。通过在单独的内核中进行评估,我们可以将代码沙箱到它自己的并行内核中。如果出现问题,我们的主内核不会受到影响。


这引出了我的要点:如何在 Mathematica 中实现异步计算?

我现在所拥有的可以工作,但它完全阻止了任何进一步的用户输入。我不能只是设置、忘记然后再检查。

有什么想法吗?

Sometimes when I'm writing experimental code in Mathematica, I'm wary as to whether I should evaluate it or not because it may end up bringing my system to it's knees.

As a contrived example if you try running the following snippet of code on a 64-bit machine, it will most likely cause your system to grind to a complete halt after it eats up all your memory.

junk = Table[{x, x}, {10^9}]; (* nom nom nom memory. Please don't run this. *)

Sure, you can just throw MemoryConstrained onto it and hope for the best, but sometimes you don't want it blocking any further input. To that end, the way I thought it might be best to achieve a middle ground was to perform the evaluation in a separate kernel.

That was decently easy enough to do:

ClearAll[GetAvailableKernel];
GetAvailableKernel[] := Block[{i, kernels},
  kernels = Kernels[];
  If[Length@kernels !=  0,
   For[i = 1, i <= Length@kernels, i++,
    If[kernels[[i, 1, 2]] > 0, Return@kernels[[i]]]
    ]
   ];
  LaunchKernels[1]]

ClearAll[SafeEvaluate];
SetAttributes[SafeEvaluate, HoldFirst];
Options[SafeEvaluate] = {"EvaluationKernel" -> Null, 
   "ConstrainMemory" -> True, "MaxMemory" -> 2 1024^3};

SafeEvaluate[expr_, OptionsPattern[]] := Block[{evalkernel, result},
  If[OptionValue["EvaluationKernel"] != Null,
   evalkernel = OptionValue["EvaluationKernel"],
   evalkernel = GetAvailableKernel[]
   ];

  result  = If[OptionValue["ConstrainMemory"],
    With[{memory = OptionValue["MaxMemory"]},
     ParallelEvaluate[MemoryConstrained[expr, memory], evalkernel]],
    ParallelEvaluate[expr, evalkernel]];
  result]

Then you could just go ahead and do something along the lines of:

SafeEvaluate[Table[{x, x}, {1024^3}]]

And Mathematica would gracefully return $Aborted telling you it ran out of memory. By evaluating in a separate kernel, we can sandbox code into it's own parallel kernel. If something goes wrong, then our main kernel isn't affected.


This brings me to my main point: How can I achieve asynchronous evaluation within Mathematica?

What I have right now works, but it completely blocks any further user input. I can't just set, forget, and check later.

Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜宝宝 2024-12-28 19:09:49

我在 Mathematica 中的并行计算经验几乎为零,所以这可能不是最好的方法,但这就是我设法挖掘的 来自文档

启动内核:

In[1]:= LaunchKernels[1]

Out[1]= KernelObject[1, "local"]

提交一些需要完成的长作业:

In[2]:= job = 
 ParallelSubmit[First@SingularValueList[RandomReal[1, {2000, 2000}]]]

Mathematicagraphics

启动作业:

In[3]:= Parallel`Developer`QueueRun[]

Out[3]= True

现在作业正在后台并行运行...

Mathematicagraphics

...我们可以在主内核中自由地做任何我们想做的事情。如果我理解你的问题,这就是你所需要的。我们可以再次运行 Parallel`Developer`QueueRun[] 来检查哪些并行评估已经完成(评估对象的显示会动态更新)。

In[4]:= 1 + 1

Out[4]= 2

等待评估完成(如果尚未完成)并收集结果:

In[5]:= WaitAll[job]

Out[5]= 1000.23

Mathematicagraphics

I have next to zero experience with parallel computation in Mathematica, so this might not be the best way, but this is what I managed to dig up from the docs:

Launch a kernel:

In[1]:= LaunchKernels[1]

Out[1]= KernelObject[1, "local"]

Submit some long to finish job:

In[2]:= job = 
 ParallelSubmit[First@SingularValueList[RandomReal[1, {2000, 2000}]]]

Mathematica graphics

Start job:

In[3]:= Parallel`Developer`QueueRun[]

Out[3]= True

Now the job is running in parallel in the background ...

Mathematica graphics

... and we're free to do whatever we want in the main kernel. If I understand your question, this is what you needed. We can run Parallel`Developer`QueueRun[] again to check which parallel evaluations have finished (the display of the evaluation object will dynamically update).

In[4]:= 1 + 1

Out[4]= 2

Wait until the evaluation finishes (if it hasn't yet) and collect the result:

In[5]:= WaitAll[job]

Out[5]= 1000.23

Mathematica graphics

命比纸薄 2024-12-28 19:09:49

通常情况下,系统会耗尽内存并开始交换。而交换会让系统慢慢死亡。在 Linux 上,这就是我所做的。

alias m804='ulimit -v 3800000; /usr/local/bin/math8.0.4/mathematica'

然后系统只是给出内存不足的消息,并在进入交换之前退出。否则行为如常。

Quite often what happens is that you system will run out of memory and start to swap. And swapping will make the system die a slow death. On Linux here is what I do

alias m804='ulimit -v 3800000; /usr/local/bin/math8.0.4/mathematica'

The system then just gives the out of memory message and quits before it goes to swap. Otherwise behaves as usual.

糖粟与秋泊 2024-12-28 19:09:49

我认为 9 年前提出这个问题时,这个功能还不存在。但对于任何在 Mathematica 12 及更高版本中寻找解决方案的人来说,您可以简单地使用 SessionSubmit[]。因此,在这种情况下,您需要 SessionSubmit[SafeEvaluate[Table[{x, x}, {1024^3}]]]。

SessionSubmit[] 函数创建一个新的任务并在当前会话中异步运行它。或者,LocalSubmit[] 可用于在单独的内核中异步运行命令,因此在较新版本的 Mathematica 中甚至不需要 SafeEvaluate 函数。更多信息请参阅 SessionSubmitLocalSubmit。此外,阅读任务对象的文档页面也可能很有用。

I don't think this functionality existed 9 years ago when this question was asked. But for anyone looking for a solution in Mathematica 12 and above, you can simply use SessionSubmit[]. So in this case you would want SessionSubmit[SafeEvaluate[Table[{x, x}, {1024^3}]]].

The SessionSubmit[] function creates a new task and runs it asynchronously in the current session. Alternatively, LocalSubmit[] can be used to asynchronously run a command in a separate Kernel, so the SafeEvaluate function wouldn't even be needed in newer versions of Mathematica. More info can be found on the documentation pages for SessionSubmit and LocalSubmit. Additionally it may also be useful read the documentation page for Task Objects.

停顿的约定 2024-12-28 19:09:49

很久以前我就使用 Mathematica,但我有一个想法。据我所知,您可以在加载 Mathematica 文档时设置自动评估功能。无法使用 Mathematica 创建一个包含 SafeEvaluate[function] 的文档作为“加载时运行”,并使用该文档在后台启动另一个 Mathematica 进程。然后您仍然可以使用您看到的输入。当然,然后您将必须汇集该进程以查看它是否结束,或者让评估功能保存您汇集的结果文件。

It was very long time ago that I used Mathematica but I had an idea. As far as I know you can set automatic evaluation of function when you load a Mathematica document. Wouldn't be possible to use Mathematica to create a document with your SafeEvaluate[function] as "run on loading" and start another Mathematica process in the background with this document. Then you can still use the one that you see for input. Of course, then you will have to pool that process to see if it ended, or have the function that evaluates save a result-file that you pool.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文