2017-01-23 12 views
1

Я пытаюсь организовать скрипты Python на малиновой Pi через Java-программу. У меня есть код Python с бесконечным циклом внутри, который считывает расстояние от ультразвукового датчика и выводит его на консоль. Код Java вызывает это как процесс оболочки, а затем считывает процесс OutputStream. Проблема, которую я испытываю, заключается в том, что данные поступают большими партиями. Вместо того чтобы я получал новое значение каждый раз, когда скрипт Python выводится на консоль, я получаю новые данные каждые 10 секунд или около того. Это проблематично, потому что я пытаюсь отобразить данные на веб-панели в режиме почти в реальном времени.Чтение из Java InputStream, сгенерированное скриптом оболочки, происходит в пакетах

Диаграмма будет выглядеть следующим образом:

DistanceController 
    |--getDistance(public) 
    |--getBufferSize(public) 
    |--buffer(private) 
    |--DistanceThread(private) 
      |--bufferReference (private) 
      |--PythonScriptProcess 

код Java выглядит следующим образом:

Это класс-оболочка, которая создает новый поток (отдельный класс) для чтения из потока вывода скрипта Python.

public class DistanceController { 
    private DistanceThread distanceThread; 
    private Thread t; 
    private LinkedList<DistanceVT> buffer = new LinkedList<DistanceVT>(); 

    public DistanceController() 
    {    
     t = new Thread(distanceThread); 
     t.start(); 
    } 

    public DistanceVT getDistance() { 
     return buffer.getLast(); 
    } 
} 

Это нить, которая читает расстояние, идея состоит в том, чтобы она была неблокирующей.

public class DistanceThread implements Runnable { 
private LinkedList<DistanceVT> buffer; 
private String[] args = new String[]{"python", "./run-scripts/distance.py"}; 

public DistanceThread(LinkedList<DistanceVT> list) {buffer = list;} 

@Override 
public void run() { 
    while (true) { 
     try { 
      ProcessBuilder pb = new ProcessBuilder(args); 
      pb.redirectErrorStream(true); 
      final Process p = pb.start(); 
      while (true) { 
       InputStream s = p.getInputStream(); 
       final BufferedReader reader = new BufferedReader(new InputStreamReader(s)); 
       while (((line = reader.readLine()) != null)) { 
        buffer.add(parseDistance(line)); 
       } 
      } 
     } catch (Exception e) { 
     //handle errors 
     } 
    } 
} 

И код Python выглядит так (слегка измененный вариант простейшего кода измерения расстояния):

import time 
import datetime 
from random import randint 

def measure_distance(): 
    time.sleep(0.1) 
    return randint(10,15) 

while True: 
    distance = measure_distance() 
    print ("%s,%s" % (datetime.datetime.now(),distance)) 
+0

Можете ли вы уменьшить код, необходимый для абсолютного минимума, для воспроизведения проблемы? –

+0

Конечно, Джим, я отредактирую свой оригинальный вопрос? –

+1

Процесс, производящий выход, буферизует его. Вы ничего не можете сделать в коде Java. Исправьте код Python. NB Нет чтения нитей из 'Reader' или' InputStream', возможно, не блокируется. Также совершенно непонятно, почему буферизация имеет значение, когда поток чтения только накапливает вывод в списке. – EJP

ответ

0

Спасибо вам всем за вашу помощь. EJP решил проблему буферизации - добавление sys.stdout.flush() в код Python разрешило проблему.

Что касается других вопросов - вы правы. Я имел в виду, что, поскольку я читаю отдельный поток, основной поток программы может продолжать выполнять другую логику.

Поток чтения накапливает данные в списке, который передается ему классом, который его создал. Затем эти данные можно получить через этот класс-оболочку, не дожидаясь завершения вывода.

import time 
import datetime 
from random import randint 
import sys 

def measure_distance(): 
    time.sleep(0.1) 
    return randint(10,15) 

while True: 
    distance = measure_distance() 
    print ("%s,%s" % (datetime.datetime.now(),distance)) 
    sys.stdout.flush()