Seite 1 von 1

Python Script langsam - schlechter Algorithmus!?

Verfasst: Dienstag 16. Juni 2015, 22:18
von Kaito90
Hallo zusammen,

ich bin noch ziemlich neu im Bereich Python und beschäftige mich momentan mit einem Script, dass sich via PySerial mit einem Arduino verbindet und fragt ab, welche Taster gedrückt wurden. Die Kommunikation funktioniert einwandfrei, nur habe ich leider ziemliche performance Probleme.

Mithilfe von ein paar clock() Befehlen konnte ich dann die übeltäter in meinem Script finden, wüsste jetzt aber nicht wie ich es besser machen sollte :?

Hier mal ein Ausschnitt aus meinem Code:

Code: Alles auswählen

arduinoDigital = "1"
arduinoAnalog = "2"
arduinoLED = "10"
arduinoDisplay = "11"
arduinoPWM = "12"
arduinoSystem = "20"

LEDon = "1"
LEDoff = "0"


def converter( thelist ):
    result =""
    a= clock()
    for element in thelist:
        str(element)
        if result != "":
            result = result +"," + element
        if result == "":
            result = element
    b=clock()
    print(b-a)
    return result

def ComInterface():
    ser = Verbindungsaufbau("off")
    while(threadFlag == 0):

        
        for i in range(0,15): #Joystickabfrage
            a = clock()
            ser.write(converter( [arduinoAnalog, format(i)] ).encode())
            b = clock()
            print("senden: ")
            print(b-a)

            x = clock()
            command = str(ser.readline().decode().strip('\r\n'))
            y= clock()
            print("empfangen: ")
            print(y-x)
            joystickNR = i
            ergebnis = joystickControl(command, joystickNR)

Code: Alles auswählen

in def ComInterface 1. Schleife
Converter:
1.3687216311453199e-05
senden: 
0.007375698689621402
empfangen: 
1.0011197853844482
Converter:
1.454266733169618e-05
senden: 
0.007338914295782928
empfangen: 
0.9980050882226639

ab der 2. Schleife
Converter:
5.132706114352459e-06
Converter:
8.554510195324383e-06
Converter:
5.98815713459544e-06
Converter:
9.409961208461937e-06
Bin für jede Hilfe dankbar. Ich denke ich habe beides zu umständlich programmiert oder ist hier Python zu langsam? Meiner Meinung nach liegt es an mir :mrgreen:
Gedacht war, dass so eine Abfrage innerhalb weniger Millisekunden durch wäre, damit ich den Arduino und die Taster als Controller benutzen kann. Habt ihr vielleicht noch bessere Ideen?

Vielen Dank

und

einen schönen Abend noch
Kaito

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Dienstag 16. Juni 2015, 23:04
von snafu
Probier mal folgendes für den Converter-Code:

Code: Alles auswählen

result = ','.join(str(elem) for elem in thelist)
Falls die Listenelemente übrigens bereits Strings sind, dann kann man sich das `str()` natürlich auch sparen.

Im Übrigen wird bei dem von dir gezeigten Code das Ergebnis von `str(element)` gar nicht verwendet. Falls das trotzdem funktioniert, dann ist entweder die Umwandlung unnötig und kann entfallen oder aber der gezeigte Code entspricht nicht exakt dem tatsächlich von dir eingesetzten Code.

Vielleicht zur Erklärung: Du erzeugst haufenweise neue Strings als Zwischenergebnisse. Das Generieren von Strings verbraucht in der Masse irgendwann spürbare Rechenzeit. Die "join"-Variante hingegen hat einen speziellen Mechanismus, um beim Hinarbeiten auf das Endresultat möglichst effizient vorzugehen.

Und wie gesagt: Guck mal, ob du das `str()` auch weglassen kannst. Das erzeugt nämlich für jedes Element einen möglicherweise unnötigen neuen String.

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 07:12
von Sirius3
@snafu: wenn element schon ein String ist, macht `str` zum Glück gar nichts.

@Kaito90: das Senden über eine serielle Schnittstelle erfolgt mit einer bestimmten Taktrate. Da kann Dein Rechnerchen noch so schnell sein, mehr als eine feste Anzahl an Zeichen pro Sekunde sind da nicht drin. Beim Empfangen kommt noch hinzu, dass die Gegenseite ja auch eine bestimmte Zeit braucht, um die Anfrage zu verarbeiten. Also von der 1 Sekunde auf die Antwort warten sind wohl 0.99 Sekunden Antwort generieren und <0.01 Sekunden Antwort senden/empfangen.

Wenn Du genau zwei Elemente einer Liste hast, nimmt man nicht join oder Dein convert sondern direkt Stringformatierung:

Code: Alles auswählen

ser.write("{},{}".format(arduinoAnalog, i).encode("ascii"))

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 08:47
von Kaito90
Morgen,

danke euch beiden für die Tipps.

@snafu: Ich meine, ich musste str(element) hinschreiben, weil er sonst rumgemeckert hat, dass es sich um ein INT handelt und das nicht in den String reingeht.

@Sirius: Wenn ich zu Hause bin, werde ich es sofort mal ausprobieren.

Ich werde dann berichten :)

Edit: Ich denke die Denksekunde beim empfangen liegt nicht beim Arduino, sondern eher an der Umwandlung:

Code: Alles auswählen

command = str(ser.readline().decode().strip('\r\n'))

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 09:01
von cofi
Nein, wie Sirius3 schon geschrieben hat ist die serielle Verbindung das Bottleneck. Die Umwandlung ist dagegen kein grosses Problem.

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 11:00
von snafu
Kaito90 hat geschrieben:Edit: Ich denke die Denksekunde beim empfangen liegt nicht beim Arduino, sondern eher an der Umwandlung:

Code: Alles auswählen

command = str(ser.readline().decode().strip('\r\n'))
Da steckt `.readline()` drin. Das gehört zu den Operationen, die auf Ein- bzw Ausgabegeräten stattfinden (Stichwort: "IO"). Diese Operationen sind im allgemeinen eher langsam, weil das angesprochene Gerät eine Weile braucht, bis es die Operation verarbeitet hat und entsprechende Rückmeldung gegeben hat. Damit muss man leider leben.

Vielleicht kannst du ja Einstellungen am Gerät oder an der Verbindung vornehmen, um hier eine schnellere Verarbeitung zu ermöglichen.

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 12:07
von Sr4l
Zeig doch mal den Code vom Arduino.

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 18:26
von Kaito90
Beim Arduino blinken die beiden LED's (RX und TX) gleichzeitig. Der gibt die Daten sofort zurück.

Code: Alles auswählen

#include <Wire.h>


void setup() {
  for (int pin = 30; pin < 54; pin++){
   //Digitale Eingänge 30 bis 53  
   pinMode(pin, INPUT); //als eingang
   digitalWrite(pin, HIGH); //pullup ein
   }
  for (int pin = 14; pin < 20; pin++){
   //Digitale Ausgänge 14 bis 19
   pinMode(pin, OUTPUT); //als ausgang
   digitalWrite(pin, LOW); //ausgang low
   }
  for (int pin = 22; pin < 30; pin++){
   //Digitale Ausgänge 22 bis 29
   pinMode(pin, OUTPUT); //als ausgang
   digitalWrite(pin, LOW); //ausgang low
   }
  for (int pin = 2; pin < 14; pin++){
   //Digitale PWM Ausgänge 2 bis 13
   pinMode(pin, OUTPUT); //als ausgang
   digitalWrite(pin, LOW); //ausgang low
   }
  Serial.begin(19200);
}





//Hauptschleife

void loop() {
 checkserial();
 
 }







/*
#####################################################

                  Funktionen

#####################################################
*/

int checkserial()
{
  int indata = 0;
  int argument1 = 0;
  int argument2 = 0;
  if (Serial.available() > 0) {
    indata = Serial.parseInt();
   
    switch(indata){
    case 1:
      argument1 = Serial.parseInt();
      checktaster(argument1);
      break;
    case 2:
      argument1 = Serial.parseInt();
      checkanalog(argument1);
      break;
    case 10:
      argument1 = Serial.parseInt();
      argument2 = Serial.parseInt();
      setled(argument1, argument2);
      break;
    case 12:
      argument1 = Serial.parseInt();
      argument2 = Serial.parseInt();
      setpwm(argument1, argument2);
      break;
    case 20:
      report();
    }
   }
  }

int report(){Serial.println("1");}

int checktaster(int pin){
  int zustand = digitalRead(pin);
  Serial.println(zustand);
}

int setled(int pin, int zustand){
  digitalWrite(pin, zustand);
}

int setpwm(int pin, int cycle){
  analogWrite(pin, cycle);}

int checkanalog(int kanal){
  switch(kanal){
    case 0:
      Serial.println(analogRead(A0));
      break;
    case 1:
      Serial.println(analogRead(A1));
      break;
    case 2:
      Serial.println(analogRead(A2));
      break;
    case 3:
      Serial.println(analogRead(A3));
      break;
    case 4:
      Serial.println(analogRead(A4));
      break;
    case 5:
      Serial.println(analogRead(A5));
      break;
    case 6:
      Serial.println(analogRead(A6));
      break;
    case 7:
      Serial.println(analogRead(A7));
      break;
    case 8:
      Serial.println(analogRead(A8));
      break;
    case 9:
      Serial.println(analogRead(A9));
      break;
    case 10:
      Serial.println(analogRead(A10));
      break;
    case 11:
      Serial.println(analogRead(A11));
      break;
    case 12:
      Serial.println(analogRead(A12));
      break;
    case 13:
      Serial.println(analogRead(A13));
      break;
    case 14:
      Serial.println(analogRead(A14));
      break;
    case 15:
      Serial.println(analogRead(A15));
      break;
  }
}











//Parkbereich
/*


//Methode 1
int checktaster()
{
   for (int pin = 30; pin < 54; pin++){
   //Digitale Eingänge 30 bis 53  
   int zustand = digitalRead(pin);
   if (zustand == LOW) {
   Serial.println(pin);
   Serial.println(zustand);}
   }
}


Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 19:12
von Kaito90
habe mich jetzt noch was eingelesen. Es scheint wohl ein Windows zu liegen. Windows wartet 40bit Times (ca. Sekunde), bevor es die bytes an die CPU gibt. Habe jetzt mal unter Windows/Anschlüsse/COM die FIFO abgestellt und den Eingangsbuffer von 14bytes auf 1 byte gestellt.

Brachte aber auch keine Abhilfe. Jedoch scheint die Software Hterm 2000 Bytes in einer Sekunde zu schicken, bekommt auch entsprechend Antwort. 180KiB/s und wieso ist das mit Python nicht möglich.

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 19:30
von Sirius3
Dein Arduino wartet auf einen Timeout, weil er das Ende Deiner Eingabe nicht anders ermitteln kann.
Korrekt müßte es also heißen:

Code: Alles auswählen

ser.write("{},{}\n".format(arduinoAnalog, i).encode("ascii"))

Re: Python Script langsam - schlechter Algorithmus!?

Verfasst: Mittwoch 17. Juni 2015, 19:45
von Kaito90
Sirius3 hat geschrieben:Dein Arduino wartet auf einen Timeout, weil er das Ende Deiner Eingabe nicht anders ermitteln kann.
Korrekt müßte es also heißen:

Code: Alles auswählen

ser.write("{},{}\n".format(arduinoAnalog, i).encode("ascii"))
peinlich :oops:

Ich hatte auch damit gerechnet, das macht PySerial für mich :] Habe jetzt eine Zeit von 0,01

Vielen Dank