I have an external program that calls Mathematica scripts upon certain events. Each script requires a large Mathematica library to load (takes a while).

Is there some way to run an initial script that loads the library, then each following script call uses the same Kernel?

  • 1
    $\begingroup$ Perhaps setup a daemon script that loads the library, then "listens" for requests for actual scripts, executes them, and pipes/stores results as needed. $\endgroup$
    – ciao
    Apr 1 '14 at 0:18

This question is old but still of interest to me, so I will offer a solution to seek feedback for improvement.

From Mathematica, we start by loading the large package (I assume you meant Mathematica library to be a package, but the solution for loaded library functions will be similar). We also record before changing the parent link, so we can return control to this session by reverting the parent link once we have finished using the kernel:

parentlink = $ParentLink;
$ParentLink = LinkCreate["Link1"];

From another session, we connect to the created link:

link = LinkConnect["Link1"];
Print[LinkRead[link]]; (* InputNamePacket[In[4]:= ] *)

Via this link, we can verify the kernel has already loaded the package via:

With[{package = package}, LinkWrite[link, Unevaluated[MemberQ[$Packages, package]]]];
Print[LinkRead[link]]; (* ReturnPacket[True] *)

We can thus execute scripts without reloading the package:

With[{script = script}, LinkWrite[link, Unevaluated[Get[script]]]];

Suppose, for whatever reason, e.g. switching from one thread to another, we need to close the link, but still want the kernel available for more scripts. Because links cannot be reused, we must regenerate the link with a different name:

LinkWrite[link, Unevaluated[$ParentLink = LinkCreate["Link2"];];

In this way, we can repeatedly close, create and connect to links to execute multiple scripts on the same kernel. Once we have finished using the kernel, we return control to the originating session via:

LinkWrite[link, Unevaluated[$ParentLink = parentlink;];

There are several issues with this solution I'm somewhat dissatisfied with, and confused about, but have yet to find answers to:

  1. The kernel's original session must be run from the notebook interface. Attempts to do so from command line result in premature termination of the kernel.
  2. Another session must be launched to connect to the kernel - I cannot figure out if it is possible to directly connect to the kernel from command line. However, I know this is possible from supported external language interfaces, so the problem is moot if your program is written in one such language.
  3. Explicitly closing a link to the kernel after writing to the link to change the kernel's parent link can result in an incomplete write, which leaves the parent link unchanged. There doesn't seem to be any way to check if writes to links have been completed. Leaving the link open and relying on session exit to close the link seems to work, but may not be guaranteed.

Your Answer

