Seite 1 von 2

Subprocess Informationen austauschen

Verfasst: Mittwoch 7. April 2021, 15:27
von bert321
Hallo,

ich beschäftige mich gerade mit dem Subprocess Modul. Im prinzip habe ich zwei Python skripte. Im main Skript möchte ich einen Subprocess starten, mit welchem dauerhaft kommuniziert werden soll.
Also ich sende vom Mainprocess fortlaufend Zahlen an den Child Process. Dieser sendet die Daten dann zurück.
Wie mach ich das?

Mein Code sieht bisher so aus:

Code: Alles auswählen

import subprocess

while True:
    publish = subprocess.Popen(
        ["/home/pi/neu/bin/python3.7",  
        "/home/pi/sktripte/rumspielen3.py"])
und der Child Prozess:

Code: Alles auswählen

while (1):
    print("hello vom Subprozess")
Die Ausgabe "hello vom Subprozess" kommt im Mainprozess schonmal an. Doch wie bekomme ich jetzt Information vom Main Prozess in den Subprozess?

Re: Subprocess Informationen austauschen

Verfasst: Mittwoch 7. April 2021, 17:55
von __blackjack__
@bert321: Da kommt keine Ausgabe in einem anderen Prozess an, die beiden Prozesse tauschen keinerlei Daten aus.

Es werden im Elternprozess auch am laufenden Band Zombieprozesse erzeugt, weil die `Popen`-Objekte nicht sauber mit `wait()` behandelt werden.

Und es werden so schnell wie es geht neue Prozesse in einer Endlosschleife gestartet von denen dann jeder in einer Endlosschleife so schnell es geht Print-Ausgaben raus haut. Eine extrem unsinnige Ressourcenverschwendung.

Was willst Du denn *eigentlich* machen? Wenn beides in Python geschrieben ist, dann wäre das vielleicht eher ein Fall für das `concurrent.futures`-Modul oder `multiprocessing`.

Re: Subprocess Informationen austauschen

Verfasst: Donnerstag 8. April 2021, 06:22
von ThomasL
so ist gut

Code: Alles auswählen

while True:
aber warum so?

Code: Alles auswählen

while (1):

Re: Subprocess Informationen austauschen

Verfasst: Donnerstag 8. April 2021, 15:42
von bert321
__blackjack__ hat geschrieben: Mittwoch 7. April 2021, 17:55 @bert321: Da kommt keine Ausgabe in einem anderen Prozess an, die beiden Prozesse tauschen keinerlei Daten aus.

Es werden im Elternprozess auch am laufenden Band Zombieprozesse erzeugt, weil die `Popen`-Objekte nicht sauber mit `wait()` behandelt werden.
Da hast du natürlich recht. Das hatte ich übersehen.
__blackjack__ hat geschrieben: Mittwoch 7. April 2021, 17:55 @bert321: Da kommt keine Ausgabe in einem anderen Prozess an, die beiden Prozesse tauschen keinerlei Daten aus.
Was willst Du denn *eigentlich* machen? Wenn beides in Python geschrieben ist, dann wäre das vielleicht eher ein Fall für das `concurrent.futures`-Modul oder `multiprocessing`.
Ich habe ein bereits fertiges Skript was für die Kommunikation über einen Bus zuständig ist und quasi in einer Endlosschleife laufen muss. Des weiteren habe ich auch noch ein C++ Programm, was genauso in einer Endlosschleife laufen muss.

Ich habe gerade mal versucht das ganze mithilfe von diesem Tutorial zu realisieren (Allerdings mit einer C++ und Python Datei): https://www.geeksforgeeks.org/python-su ... languages/
Hier habe ich quasi zwei dateien erstellt. Ein Python Skript mit:

Code: Alles auswählen

import subprocess
import os


def executeCpp():
    # create a pipe to a child process
    data, temp = os.pipe()

    # write to STDIN as a byte object(convert string
    # to bytes with encoding utf8)
    os.write(temp, bytes("5 10\n", "utf-8"));
    os.close(temp)

    # store output of the program as a byte string in s
    s = subprocess.check_output("g++ HelloWorld.cpp -o out2;./out2", stdin=data,shell=True)

    # decode s to a normal string
    print(s.decode("utf-8"))


if __name__=="__main__":
    while True:
        executeCpp()
/[code]
und eine C++ Datei mit:
[code]
#include <iostream>
using namespace std;
int main()
{
    int a, b;
    cin >> a >> b;
    
     cout << "Hello World from C++.Values are:" << a << " " << b;
    
    return 0;
}
Funktioniert auch soweit. Nur sobald ich in der C++ Datei den Part mit cout in eine while schleife setze, also so:

Code: Alles auswählen

#include <iostream>
using namespace std;
int main()
{
    int a, b;
    cin >> a >> b;
    
     cout << "Hello World from C++.Values are:" << a << " " << b;
    
    return 0;
}
kommt in meinem Python Skript nichts mehr an.
Ist meine Vermutung richtig, dass ich mit subprocess.check_output nur den C++ Code einmal kurz starte, warte bis es durchgelaufen ist und dann die Ausgabe aus dem C++ Code bekomme? Also ist das Problem dass das so nicht funktionieren kann?

ThomasL hat geschrieben: Donnerstag 8. April 2021, 06:22 aber warum so?

Code: Alles auswählen

while (1):
Dachte das wäre äquivalent, bisher...

Re: Subprocess Informationen austauschen

Verfasst: Donnerstag 8. April 2021, 16:13
von Sirius3
Wenn Du ein Programm mit Endloschleife hast, ist das doch etwas anderes, als Endlos ein Programm immer wieder zu starten.`

`check_output` wartet, bis das Programm beendet ist, also bei einem Programm mit einer Endlosschleife endlos.
Du brauchst also Popen und mußt in einer Schleife stdout lesen.

`while (1):` macht von außen schon das selbe wie `while True:`, zweiteres ist aber halt viel lesbarer. Da sind zum einen die unnötigen Klammern, wo man sich fragt, warum ist der Ausdruck geklammert. Dann muß der Interpreter jedesmal prüfen ob 1 zu True oder False evaluiert (naja, wenn es der Compiler nicht wegoptimieren würde).

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 13. April 2021, 06:13
von bert321
so, jetzt komm ich endlich mal wieder dazu mich hier zu melden.
Sirius3 hat geschrieben: Donnerstag 8. April 2021, 16:13 `check_output` wartet, bis das Programm beendet ist, also bei einem Programm mit einer Endlosschleife endlos.
Du brauchst also Popen und mußt in einer Schleife stdout lesen.
Genau das hatte ich quasi schon vermutet.
Ich habe zu deinem Tipp das hier gefunden: https://stackoverflow.com/questions/367 ... thon-and-c
Fraglich ist für mich nur, was der erste Part seine Codes macht. Also das hier:
proc = subprocess.Popen("C:\Python27\PythonPipes.exe",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
Wird hiermit das C++ Programm gestartet?

Wenn ich das ganze dann in Stdin/Stdout printe ist doch quasi meine Konsole mit den Informationen die hier ausgetauscht werden zugemüllt und ich kann Ausgaben, die vom Code zwecks debugging erzeugt werden garnicht mehr richtig herausfiltern?

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 13. April 2021, 07:56
von Sirius3
Dann printe es doch einfach nicht.

Re: Subprocess Informationen austauschen

Verfasst: Freitag 16. April 2021, 13:45
von bert321
ja gut, aber das ist dann trotzdem keine Lösung für diese Problem:
bert321 hat geschrieben: Dienstag 13. April 2021, 06:13 Ich habe zu deinem Tipp das hier gefunden: https://stackoverflow.com/questions/367 ... thon-and-c
Fraglich ist für mich nur, was der erste Part seine Codes macht. Also das hier:
proc = subprocess.Popen("C:\Python27\PythonPipes.exe",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
Wird hiermit das C++ Programm gestartet?
Kann mir da evtl. jemand weiterhelfen?

Re: Subprocess Informationen austauschen

Verfasst: Freitag 16. April 2021, 13:49
von __deets__
Verstehe ich nicht. Wenn du Ausgaben deines Programms bekommst, dann wird das doch gestartet worden sein. Woher sonst sollen die kommen?

Re: Subprocess Informationen austauschen

Verfasst: Freitag 16. April 2021, 20:13
von __blackjack__
@bert321: Ja, mit `Popen` wird das externe Programm gestartet. Und danach muss man dann dafür sorgen, dass die Standardein- und ausgabe von dem Prozess entsprechend ”bedient” werden. Wenn das beispielsweise zwei Zahlen als Zeichenketten erwartet, bevor es selbst etwas ausgibt, dann muss man natürlich erst diese beiden Werte an das Programm übermitteln, bevor man die Ausgabe auslesen kann. Wobei es auch von dem externen Programm abhängen kann ob es überhaupt ausreicht nur die Zeichenkette(n) zu schreiben, oder ob man die Standardeingabe des Prozesses eventuell auch schliessen muss, bevor das Programm die Daten verarbeitet.

Es lässt sich nicht so allgemein jedes Programm auf diese Weise ansprechen, weil das Betriebssystem oder die C- oder C++-Laufzeitbibliothek eventuell auch Daten blockweise puffern.

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 15:54
von bert321
Alles klar, dass mit dem Popen hat mir schon weitergeholfen.

Mein Code sieht jetzt so aus:

Code: Alles auswählen

import subprocess

proc = subprocess.Popen("/home/pi/test.sh",stdin=subprocess.PIPE,stdout=subprocess.PIPE)

state = "run"
while state == "run":
    input = input("first") #Nachricht, die an C++ Skript gesendet wird. Es sollte First Hello! zurückkommen

    if input == "quit":
        state = "terminate" # any string other than "run" will do

    proc.stdin.write(input + "\n")
    cppMessage = proc.stdout.readline().rstrip("\n")
    print ("cppreturn message ->" + cppMessage + " written by python \n")
    print ("test")
Meine test.sh sieht so aus:

Code: Alles auswählen

#!/bin/bash
g++ -o Test1 /home/pi/helloFromC.cpp
sudo ./Test1
Der C++ Code:

Code: Alles auswählen

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char* args[]){

    string python_message = "";
    bool quit = false;

    while (!quit){
        cin >> python_message;

        if (python_message == "quit"){
            quit = true;
        }
        else if (python_message == "first"){
            cout << "First Hello!" << endl;
        }
        else if (python_message == "second"){
            cout << "Second Hello!" << endl;
        }
        else if (python_message == "third"){
            cout << "Third Hello!" << endl;
        }
        else {
            cout << "Huh?" << endl;
        }
    }
    return 0;
}
Wenn ich nun das Pythonskript starte wird "first" in der Konsole ausgegeben. Dann scheint es jedoch zu hängen. Mein in der letzter Zeile geschriebener print "test" wird nicht ausgegeben. Warum?

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 16:34
von Sirius3
Du solltest die eingebaute Funktion `input` nicht durch die Variable `input` überdecken. Würdest Du, wie es sich gehört, alles in einer Funktion stehen haben, würde Dir das auch gleich mit der richtigen Fehlermeldung beschieden.
Wenn Du eine while-Schleife hast, die nur durch einen Dummy-Wert überhaupt startet, hast Du eigentlich eine while-True-Schleife:

Code: Alles auswählen

import subprocess

def main():
    proc = subprocess.Popen("/home/pi/test.sh", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    while True:
        command = input("first") #Nachricht, die an C++ Skript gesendet wird. Es sollte First Hello! zurückkommen
        proc.stdin.write(command + "\n")
        proc.stdin.flush()
        cpp_message = proc.stdout.readline().rstrip("\n")
        print(f"cppreturn message -> {cpp_message} written by python")
        print("test")
        if command == "quit":
            break

if __name__ == '__main__':
    main()
Nach der Ausgabe solltest Du die Buffer flushen. Das hat Dir __blackjack__ schon geraten, und das solltest Du in Deinem C-Programm genauso tun.

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 17:04
von __blackjack__
Warum um alles in der Welt wird das übersetzte C++-Programm eigentlich mit ``sudo`` gestartet? 😱

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 18:31
von __deets__
Wenn du Kontrolle über den C++ code hast, dann gibt es deutlich bessere Möglichkeiten zum Datenaustausch. Zb UNIX Domain Sockets, oder FIFOs, oder Bibliotheken wie ZeroMQ oder Nanomsg.

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 19:01
von __blackjack__
Was ist denn an UNIX Domains Sockets oder FIFOs besser? Ich meine das sind doch letztlich auch Dateien, aber nicht so portabel wie direkt über die Standardein- und Ausgabe-Dateien zu kommunizieren.

Re: Subprocess Informationen austauschen

Verfasst: Montag 19. April 2021, 22:43
von __deets__
Meines Erachtens ist deren Semantik freundlicher. Flush zumindest musste ich noch nie nutzen. Oder vertue ich mich da gerade?

Spätestens bei zeromq und Nanomsg sind die Vorteile aber unzweifelhaft. Message orientiert, verschiedene Semantiken (pipes, req/response), automatisch verbindend etc.

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 20. April 2021, 09:35
von bert321
Sirius3 hat geschrieben: Montag 19. April 2021, 16:34 Du solltest die eingebaute Funktion `input` nicht durch die Variable `input` überdecken. Würdest Du, wie es sich gehört, alles in einer Funktion stehen haben, würde Dir das auch gleich mit der richtigen Fehlermeldung beschieden.
Wenn Du eine while-Schleife hast, die nur durch einen Dummy-Wert überhaupt startet, hast Du eigentlich eine while-True-Schleife:
Nach der Ausgabe solltest Du die Buffer flushen. Das hat Dir __blackjack__ schon geraten, und das solltest Du in Deinem C-Programm genauso tun.
Danke für deinen Tipp. Leider funktioniert dein Code auch nicht. Es kommt wieder lediglich nur die Ausgabe "first" und sonst nichts. Oder liegt das daran, dass ich mich nocht nicht darum gekümmert habe die Buffer zu flushen?
__blackjack__ hat geschrieben: Montag 19. April 2021, 17:04 Warum um alles in der Welt wird das übersetzte C++-Programm eigentlich mit ``sudo`` gestartet? 😱
Hatte das so aus einem Tutorial

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 20. April 2021, 10:10
von Sirius3
An Deinem C-Code habe ich ja nichts geändert.

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 20. April 2021, 11:20
von bert321
Wenn ich den C-Code aber eigenständig starte funktioniert er.
Woran liegt das eigentlich, dass so Beispiele aus dem Internet gefühlt nie funktionieren? :shock:

Re: Subprocess Informationen austauschen

Verfasst: Dienstag 20. April 2021, 11:53
von __deets__
Weil dein Programm dann in ein terminal ausgjbt. Und das liefert Daten zeilenweise aus. Eine Pipe hingegen ohne flush Buffert gerne mehrere KB.