17

I have two notebooks, each with a different kernel. Is there a way to grab the value of a variable in KernelA from KernelB?

Sjoerd C. de Vries
  • 65,815
  • 14
  • 188
  • 323
M.R.
  • 31,425
  • 8
  • 90
  • 281
  • You could try assigning the variable to a tagging rule and accessing via CurrentValue[$FrontEndSession,{TaggingRules, ...}] – Mike Honeychurch Nov 05 '12 at 21:58
  • 2
    You could use a file. – Sjoerd C. de Vries Nov 05 '12 at 21:59
  • @MikeHoneychurch interesting approach, an you give all the code for your example as a solution? – M.R. Nov 05 '12 at 22:06
  • 1
    IMO probably the best way is using MathLink (Mike's suggestion of course uses it indirectly). I showed how you can link up two kernels here--you may be interested in the linked MathGroup posting too. An updated version of that code is here. – Oleksandr R. Nov 05 '12 at 22:12
  • @OleksandrR. Could you update your answer with the latest version of the code? (you can perhaps use belisarius' notebook-in-image palette to upload it if it is long) – rm -rf Nov 05 '12 at 22:28
  • @OleksandrR. Yeah, sure that would be a fine place. Do you have an account? If so, I can add you to the repo. If not, I'll upload it – rm -rf Nov 05 '12 at 22:44

2 Answers2

12

Try this out:

Lets say you have a variable called kernelA in one notebook using Kernel A. Then:

CurrentValue[$FrontEndSession, {TaggingRules, "KernelA"}] = kernelA

In your other notebook, running Kernel B just evaluate

variableFromOthernotebook = CurrentValue[$FrontEndSession, {TaggingRules, "KernelA"}]

Edit

An alternative that might be faster (almost certainly would be if a lot of TaggingRules are used).

SetOptions[$FrontEndSession, TaggingRules -> {"KernelA" -> kernelA}]

than in the other notebook:

variableFromOthernotebook = "KernelA" /. 
(TaggingRules /. Options[$FrontEndSession, TaggingRules])
Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158
  • There is significant lag in this example :( – M.R. Nov 06 '12 at 01:06
  • @M.R. can you explain what you mean? A lag setting the value? A lag obtaining the value? – Mike Honeychurch Nov 06 '12 at 05:34
  • 1
    @MikeH. I find your method surprisingly performant, with no obvious lag, as well as ingenious in its simplicity. A lot of optimization must go in to the front-end link, as its bandwidth for large transfers is actually higher than the approach I demonstrate (although it has a marginally higher latency). As usual, though, older versions win out in the performance stakes: using my example, Mathematica 5.2 is about twice as fast as version 8 for basic MathLink transfers... – Oleksandr R. Nov 06 '12 at 05:46
  • @OleksandrR. In the past I have found that if you have to set a large number of rules (from memory 30-50), TaggingRules can slow down quite a bit but for a small number I have found it to be fairly efficient. Why is V5.2 faster than V8 for MathLink transfers? – Mike Honeychurch Nov 06 '12 at 06:34
  • @MikeH. I don't really know why, but it seems with each new version, along with many new features, more overhead gets added to the fundamental operations. In this case it's probably a question of MathLink interface version 2 vs. 3, the latter being slower for some reason. Basic manipulation of DownValues is also about a third faster in 5.2 than 8. – Oleksandr R. Nov 06 '12 at 13:20
  • @MikeHoneychurch By lag I mean, that if you change the value dynamically in one notebook, the other lags behind: Slider[Dynamic[ CurrentValue[$FrontEndSession, {TaggingRules, "Alpha"}]], {0, 100}] – M.R. Nov 06 '12 at 17:51
  • @M.R. Your question merely asks how to grab a variable from one kernel in another: no mention of dynamics and sliders or ultimate intended usage. If the answer disappoints isn't it fair to say that the question has insufficient information? – Mike Honeychurch Nov 07 '12 at 19:15
  • @MikeHoneychurch It's a great answer. I should have asked "How can I (dynamically and/or most quickly) access a variable in one evaluator from another evaluator?" – M.R. Nov 08 '12 at 04:05
  • @M.R. I have found TaggingRules to be slow if you have to use CurrentValue when there are a lot of tagging rules defined. In those cases I have found it more efficient to use SetOptions. You might want to try that and see if it helps. See edit. – Mike Honeychurch Nov 08 '12 at 06:34
11

Here is a very simple example of how to use MathLink for this sort of communication. I will use normal code blocks for kernel A and quoted code blocks for kernel B. You must evaluate these in the order shown.

link = LinkCreate["a uniquely named link"];
link = LinkConnect["a uniquely named link"];
LinkActivate[link];
MathLink`AddSharingLink[link];
LinkActivate[link];
SetAttributes[remoteEvaluate, HoldAllComplete];
remoteEvaluate[expr_] := (
  LinkWrite[link, Unevaluated@EvaluatePacket[expr]]; LinkFlush[link];
  First@Cases[
    While[Sow[#, Head[#]] &[LinkRead[link]]; LinkReadyQ[link]] ~Reap~ ReturnPacket,
    ReturnPacket[result_] :> result, {3}
   ]
 );

The idea is that the result of evaluating expr on kernel B comes back to kernel A as the body of a ReturnPacket. Other types of packets may also be produced (for example, ExpressionPackets are generated when something is Printed), but we ignore these for present purposes.

Now:

var = Range[5];
var
(* -> var *)

remoteEvaluate[var]
(* -> {1, 2, 3, 4, 5} *)

If we care to check, we will also find that var did not suffer the indignity of unpacking and was quite unmolested in general by this process.

One important point to note is that it is not legal to call MathLink`AddSharingLink on the same link from two different kernels, as this causes a deadlock. Therefore, if you want to share data in a symmetric fasion, you will have to set up a link from A to B and another link from B to A. Although links are in fact bidirectional, this sort of communication requires matching reads and writes to be placed on the link in the appropriate sequence. Unless A and B are both being controlled by C, it will be easier in many cases to defer to the main loop as shown above, because although it renders each link effectively unidirectional, it also enables single-ended communication.

Oleksandr R.
  • 23,023
  • 4
  • 87
  • 125