Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple stdin/stdout actions during one process call

I use Google Closure Compiler to compile automatically javascript using PHP (is needed to do it that way - in PHP, hovewer no security limitations on Windows machine). I wrote simple PHP script which calls process, pass .js content to stdin and receive recompiled .js via stdout. It works fine, problem is, when I compiling for example 40 .js files, it takes on strong machine almost 2 minutes. However, mayor delay is because java starts new instance of .jar app for every script. Is there any way how to modify script below to create process only one and send/receive .js content multiple times before process ends?

function compileJScript($s) {
    $process = proc_open('java.exe -jar compiler.jar', array(
        0 => array("pipe", "r"), 1 => array("pipe", "w")), $pipes);
    if (is_resource($process)) {
        fwrite($pipes[0], $s);
        fclose($pipes[0]);
        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        if (proc_close($process) == 0) // If fails, keep $s intact
            $s = $output;
    }
    return $s;
}

I can see several options, but don't know if it is possible and how to do it:

  1. Create process once and recreate only pipes for every file
  2. Force java to keep JIT-ed .jar in memory for much faster re-executing
  3. If PHP can't do it, is possible to use bridge (another .exe file which will start fast every time, transfer stdin/out and redirects it to running compiler; if something like this even exists)
like image 381
micropro.cz Avatar asked Sep 10 '14 01:09

micropro.cz


1 Answers

This is really a matter of coordination between the two process.

Here I wrote a quick 10-minutes script (just for the fun) that launches a JVM and sends an integer value, which java parses and returns incremented.. which PHP will just send it back ad-infinitum..

PHP.php

<?php

echo 'Compiling..', PHP_EOL;
system('javac Java.java');

echo 'Starting JVM..', PHP_EOL;
$pipes = null;
$process = proc_open('java Java', [0 => ['pipe', 'r'],
                                   1 => ['pipe', 'w']], $pipes);

if (!is_resource($process)) {
  exit('ERR: Cannot create java process');
}

list($javaIn, $javaOut) = $pipes;

$i = 1;

while (true) {

  fwrite($javaIn, $i); // <-- send the number
  fwrite($javaIn, PHP_EOL);
  fflush($javaIn); 

  $reply = fgetss($javaOut); // <-- blocking read
  $i = intval($reply);

  echo $i, PHP_EOL;
  sleep(1); // <-- wait 1 second
}

Java.java

import java.util.Scanner;

class Java {

  public static void main(String[] args) {

    Scanner s = new Scanner(System.in);

    while (s.hasNextInt()) { // <-- blocking read
      int i = s.nextInt();
      System.out.print(i + 1); // <-- send it back
      System.out.print('\n');
      System.out.flush();
    }
  }
}

To run the script simply put those files in the same folder and do

$ php PHP.php

you should start seeing the numbers being printed like:

1
2
3
.
.
.

Note that while those numbers are printed by PHP, they are actually generated by Java

like image 179
eridal Avatar answered Sep 27 '22 22:09

eridal