11

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?

Mike Bailey
  • 12,479
  • 14
  • 66
  • 123
  • You elaborately describe `SafeEvaluate` yet you spend few words on your actual question and I am left guessing its meaning. Are you looking for a way to evaluate an expression in one cell, leave the evaluation running, and evaluate an expression in a second cell, potentially getting the result before the evaluation of the first cell completes? – Mr.Wizard Dec 15 '11 at 08:55
  • @Mr.Wizard That's my reading of the question. My first thought was that this is impossible because any evaluation will change the kernel state. Therefore two parallel evaluations would simulationeously change the kernel state: Mike is in fact asking for multithreading, with all the difficulties and subtleties that it brings up. (Even with parallel kernels, some of the state evenutally gets shared to get back the results.) But then I thought of `Dynamic[f[i]]`, `Table[Pause[1]; i, {i, 10}]` (try it---it's like `Monitor`). This is in fact evaluating things in parallel, in a single kernel. – Szabolcs Dec 15 '11 at 09:13
  • @Szabolcs where does he say he wants parallel evaluation within a single kernel? – Mr.Wizard Dec 15 '11 at 09:18
  • @Mr.Wizard My point was that sharing of the kernel state between evaluations may not be a problem, not suggesting that it should be done using a single kernel. I would find it useful to be able to start a new evaluation before the previous one has finished, *and* have all the previous definitions shared between the evaluations. – Szabolcs Dec 15 '11 at 09:39

4 Answers4

8

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

Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • Another set of functions I haven't used. +1 for that alone! – Mr.Wizard Dec 15 '11 at 14:55
  • @Mr.Wizard First I wanted to do something similar to the example [here](http://reference.wolfram.com/mathematica/ref/EvaluatePacket.html), then I realized that would be re-implementing the parallelization functionality (which already has `DistributeDefinitions`!), so I searched the docs some more. I didn't know these functions either. – Szabolcs Dec 15 '11 at 14:58
3

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.

  • Anything for Windows? http://stackoverflow.com/questions/7854980/correct-way-to-cap-mathematica-memory-use – Mr.Wizard Dec 15 '11 at 10:03
  • I am not a Windows person, someone else would need to comment on this matter. –  Dec 15 '11 at 10:21
  • I've tried using `ulimit` a few times for different purposes and it never really works on a mac. On linux, I think you need to have admin privileges, which is why I couldn't get it to run on my group server. – abcd Dec 15 '11 at 15:14
  • No, I have this ulimit stuff in my .bashrc no admin rights for -v. –  Dec 15 '11 at 15:57
2

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.

Partial Science
  • 330
  • 2
  • 6
0

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.

Lucian
  • 3,407
  • 2
  • 21
  • 18