12

I have written a Mathematica script that is to be run periodically on a Raspberry Pi. The code takes about 3 seconds to execute if I test it in a CLI Mathematica session. However, when I execute the script with

wolfram -script script.w > out.csv

it takes more than 10 seconds. The output of the script is a single String three ASCII characters long, so writing output to file does not take a significat part of the time. I thus assume most of the extra time comes from kernel initialization.

I'd like to initialize Mathematica kernel once and then run my script periodically without needing to initialize the kernel every time. Is this possible?


UPDATE

Following the answer from this related question I tried to make it work like this:

mkfifo mmpipe
tail -f mmpipe | wolfram -noprompt &

However, when I pipe a command that contains a file-importing function like ReadList, it stays in interactive mode and does not exit to shell:

echo 'ReadList["/home/pi2/data.csv","String"]'>mmpipe
{ ... , "2014/02/05 21:35:02,0.28", "2014/02/05 21:40:02,0.00", "2014/02/05 21:50:02,0.00"}
_

So I can't use it in an automated process.

shrx
  • 7,807
  • 2
  • 22
  • 55
  • Probably you could keep the kernel running and send the scripts using MathLink. – rhermans Feb 05 '14 at 15:44
  • 1
    You could use the scheduled tasks functionality of Mathematica, and set up a task to be run every 30 minutes. I.e. don't schedule this using an external tool. Schedule it within Mathematica. Does this help? – Szabolcs Feb 05 '14 at 16:17
  • Is .w the recommended extension for packages/scripts now? :-/ – Szabolcs Feb 05 '14 at 16:17
  • @rhermans I've never used MathLink before. Could you explain a bit? @Szabolcs I know about this but my script depends on the output of some other non-Mathematica scripts that are executed before it, so I'd prefer to keep cron as the main task schedule manager. – shrx Feb 05 '14 at 19:37
  • 1
    Found a closely related question: http://mathematica.stackexchange.com/questions/23217/keep-mathkernel-running-in-background-speed-up-execution-time – shrx Feb 05 '14 at 19:57
  • 1
    @shrx MathLink is a communication protocol used by Mathematica and a corresponding API (has ready-made bindings for C/C++/Java/.NET). The kernel and the front end communicate through MathLink. The main kernel and subkernels used in parallel calculations also communicate through MathLink. You could theoretically write alternative front ends using MathLink. Some people have: there's something Emacs-based and two shell-based ones: jmath and mash. I never tried these. But if you were to ... – Szabolcs Feb 06 '14 at 21:07
  • ... write a MathLink program to continually feed arbitrary expressions to Mathematica for evaluation, you'd probably end up with something fairly similar to these two, so they might be worth a look for you. If you know C and you're willing to spend the time to learn the MathLink API, it wouldn't be very difficult to write a C program for your purposes. It probably wouldn't be longer than a hundred lines in total. – Szabolcs Feb 06 '14 at 21:09
  • Thanks for the explanation. I don't know any C or java, most of my scripts are just bash and some python. So learning to use MathLink seems too much work for what I need, and my solution is good enough for now. – shrx Feb 06 '14 at 21:18
  • Have you any idea how to get this to work no windows? – William Aug 05 '15 at 03:58
  • @William sorry, can't help you there. I gave up on Windows long ago. – shrx Aug 05 '15 at 07:15

1 Answers1

3

Alright, I managed to make a clunky working script with the help from @Szabolcs' answer here and some testing of the fifo procedure:

#!/bin/bash

pipe=/home/pi2/mmpipe

# check if pipe exists; if not, create it
if [[ ! -p $pipe ]]; then
    mkfifo $pipe
fi

# check if kernel is running; if not, start it and define functions
if [ $(ps aux | grep WolframKernel | grep -v grep | wc -l) -eq 0 ]; then
 tail -f $pipe | wolfram -noprompt &
    sleep 6 # this is needed; functions need to wait for the kernel to initialize
    echo 'function1[]:=...'>$pipe
 sleep 1 # this is also needed; kernel needs some time with each new definition
 echo 'function2[]:=...'>$pipe
fi

echo 'run main mathematica code here;'>$pipe

This solution works only if Mathematica code does not output anything. Every line needs to end with ; and Print[] should not be used. Otherwise the script stays in interactive mode and does not exit to shell. Mathematica output can be saved with Export[], though.


UPDATE

I'm having some trouble with this solution. After some time of working without problems, the second defined function (I have only two) is no longer evaluated. Running echo '?function2'>$pipe returns only "Global`function2" like its definition was somehow unset. I have managed to incorporate the second function in the main code and leave it out from the initial definitions, but this method proves to be really unreliable.

shrx
  • 7,807
  • 2
  • 22
  • 55