Hi,
ich habe nun mein ganzen "Webservice" mal unter einem baugleichen RPI getestet.
Das Result:
Der RPI ist genauso langsam bei den Aufrufen. Also wird es wahrscheinlich an dem RPI liegen. Das Modell hat wahrscheinliche einfach nicht genug Kapazitäten um diesen Dienst auszuführen...
Ich werde mir noch ein RPI vom Typ B2 anlegen und mal schauen, wie der mit dem Webservice zurecht kommt.
Django Request langsam
@xerion21: Das kann nicht sein. Ein Raspi, auch einer der ersten Generation, ist in der Lage ein einfaches SELECT von 100 Datensätzen aus einer SQLite-DB abzufragen und als Webseite aufzubereiten und auszuliefern ohne dafür *10* *Sekunden* zu brauchen. Das muss irgendwo ein Problem beim Code sein.
Schau Dir mal den CPU-Verbrauch während der 10 Sekunden kontinuierlich an. Falls die CPU durchgehend ackert, dann macht der Code sehr wahrscheinlich irgend etwas ungünstiges. Falls die CPU dagegen die meiste Zeit nichts macht, dann blockiert irgend etwas und der Rechner wartet auf einen Timeout. Dann müsste man dann heraus finden warum und auf was gewartet wird.
Schau Dir mal den CPU-Verbrauch während der 10 Sekunden kontinuierlich an. Falls die CPU durchgehend ackert, dann macht der Code sehr wahrscheinlich irgend etwas ungünstiges. Falls die CPU dagegen die meiste Zeit nichts macht, dann blockiert irgend etwas und der Rechner wartet auf einen Timeout. Dann müsste man dann heraus finden warum und auf was gewartet wird.
Die Frage ist dann, warum der Code in meiner VM, der ich die gleichen Ressourcen gegeben habe wie der RPI, diesen Code ohne Probleme abhandelt.BlackJack hat geschrieben:@xerion21: Das kann nicht sein. Ein Raspi, auch einer der ersten Generation, ist in der Lage ein einfaches SELECT von 100 Datensätzen aus einer SQLite-DB abzufragen und als Webseite aufzubereiten und auszuliefern ohne dafür *10* *Sekunden* zu brauchen. Das muss irgendwo ein Problem beim Code sein.
Schau Dir mal den CPU-Verbrauch während der 10 Sekunden kontinuierlich an. Falls die CPU durchgehend ackert, dann macht der Code sehr wahrscheinlich irgend etwas ungünstiges. Falls die CPU dagegen die meiste Zeit nichts macht, dann blockiert irgend etwas und der Rechner wartet auf einen Timeout. Dann müsste man dann heraus finden warum und auf was gewartet wird.
Der CPU-Verbrauch ist während der Anfrage kontinuierlich auf 95%.
Ich weiß leider nicht mehr weiter... Ich kann euch den Code gerne zur Verfügung stellen, sagt mir jediglich was ihr von dem Code benötigt.
@xerion21: Naja, man bräuchte alles um das Problem nachstellen zu können. Also ein Short, Self Contained, Correct (Compilable), Example.
Das Problem ist, dass ich euch die Datenbank mit den Daten leider nicht zur Verfügung stellen kann, aus datenschutztechnischen Gründen...BlackJack hat geschrieben:@xerion21: Naja, man bräuchte alles um das Problem nachstellen zu können. Also ein Short, Self Contained, Correct (Compilable), Example.
Die restlichen Scripte kann ich euch gerne zur Verfügung stellen
wie gesagt, laut der django toolbar dauert die DB-Abfrage 40ms. Ich hatte leider noch keine Zeit, dies zu testen. Dies werde ich heute abend tun.Sirius3 hat geschrieben:@xerion21: wobei wir wieder bei der Frage von vor x Posts wären: Ist die Datenbankabfrage das Bottleneck?
@xerion21: Das Beispiel muss ja nur das Problem illustrieren/nachvollziehbar machen. Füll die DB mit gleich Zufallsdaten die die gleichen Eigenschaften haben, prüfe ob das Problem damit immer noch besteht, und dann kannst Du das ja herzeigen und wir können auch auf die Suche gehen.
Mal wild geraten: Ist es möglicherweise eine schlechte Idee, "timesince" auf dem Raspi in einer Schleife aufzurufen? Da wird ja sicherlich die aktuelle Zeit vom System abgefragt. Vielleicht ist das ja langsam, wenn man es für 100 Spieler macht? Wäre zwar komisch, aber da der ganze Sachverhalt seltsam klingt, kommt ja erstmal alles mögliche in Betracht...xerion21 hat geschrieben:Code: Alles auswählen
<a class="lead" href="/player/show/{{ player.id }}">{{ player.lastname }}, {{ player.firstname }}</a> {% if player.birthday %} <br><b>Geburtstag: </b>{{player.birthday|date:"d.m.Y"|linebreaksbr }} {% endif %} <br><b>Erstellt vor: </b>{{ player.date_created|timesince }}
Vielleicht nimmst du einfach mal die letzte Zeile aus dem Template raus und guckst, ob sich was verändert hat.
Werde ich heute abend mal testen. Das Problem ist, dass die langsame Geschwindigkeit auch bei anderen Templates auftritt. So auch bei diesem:snafu hat geschrieben:Mal wild geraten: Ist es möglicherweise eine schlechte Idee, "timesince" auf dem Raspi in einer Schleife aufzurufen? Da wird ja sicherlich die aktuelle Zeit vom System abgefragt. Vielleicht ist das ja langsam, wenn man es für 100 Spieler macht? Wäre zwar komisch, aber da der ganze Sachverhalt seltsam klingt, kommt ja erstmal alles mögliche in Betracht...xerion21 hat geschrieben:Code: Alles auswählen
<a class="lead" href="/player/show/{{ player.id }}">{{ player.lastname }}, {{ player.firstname }}</a> {% if player.birthday %} <br><b>Geburtstag: </b>{{player.birthday|date:"d.m.Y"|linebreaksbr }} {% endif %} <br><b>Erstellt vor: </b>{{ player.date_created|timesince }}
Vielleicht nimmst du einfach mal die letzte Zeile aus dem Template raus und guckst, ob sich was verändert hat.
Code: Alles auswählen
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{% if create %}Erstelle{% else %}Bearbeite{% endif %} Spieler{% endblock %}
{% block heading %}
{% if create %}Erstelle Spieler{% else %}Bearbeite Spieler{% endif %}
{% endblock %}
{% block content %}
{% if create %}
{% url "Spielerdatenbank_player_create" as action_url %}
{% else %}
{% url "Spielerdatenbank_player_edit" player.pk as action_url %}
{% endif %}
<form action="{{ action_url }}" method="post" accept-charset="utf-8">
{{ form|crispy }}
{% csrf_token %}
<p><input type="submit" class="btn btn-default" value="Speichern" /></p>
</form>
{% endblock %}
Code: Alles auswählen
class Player(models.Model):
firstname = models.CharField('Vorname', max_length = 20)
lastname = models.CharField('Nachname', max_length = 30)
gender = models.CharField('Geschlecht', max_length = 1, choices = [ ('M', 'Männlich'), ('W', 'Weiblich') ] )
birthday = models.DateField('Geburtstag')
address = models.ForeignKey(Address, verbose_name = 'Adresse', related_name = 'player_address')
phone_privat = models.CharField('Telefon Privat', max_length = 20, blank = True)
phone_handy = models.CharField('Handy', max_length = 20, blank = True)
phone_work = models.CharField('Telefon Arbeit', max_length = 20, blank = True)
email_privat = models.EmailField('Email Privat', blank = True)
email_work = models.EmailField('Email Arbeit', blank = True)
email_club = models.EmailField('Email Verein', blank = True)
mother = models.ForeignKey(Parent, verbose_name = 'Mutter', related_name = 'player_mothers', null = True, blank = True)
father = models.ForeignKey(Parent, verbose_name = 'Vater', related_name = 'player_fathers', null = True, blank = True)
club = models.ForeignKey(Club, verbose_name = 'Verein', related_name = 'player_clubs')
# Beitrittsjahr Verein?
club_entry = models.DateField('Beitrittsdatum Verein')
is_supporter = models.BooleanField('Mitglied Förderverein', default = False)
date_supporter = models.DateField('Beitrittsdatum Förderverein', blank = True, null = True)
# Förderverein (Beitritt)
passnumber = models.CharField('Passnummer', max_length = 15, validators = [ RegexValidator(r'^[0-9 ]*$', 'Passnummer falsch') ] )
play_eligibility = models.DateField('Spielberechtigt seit')
position_attack = models.ForeignKey(PositionAttack, verbose_name = 'Position Angriff', null = True, blank = True)
position_defence = models.ForeignKey(PositionDefence, verbose_name = 'Position Abwehr', null = True, blank = True)
handed = models.CharField('Wurfhand', max_length = 1, choices = [ ('L', 'links' ), ('R', 'rechts') ], null = True, blank = True)
body_weight = models.DecimalField('Körpergewicht', help_text = 'in kg', max_digits = 4, decimal_places = 1, blank = True, null = True)
body_height = models.DecimalField('Körpergröße', help_text = 'in cm', max_digits = 3, decimal_places = 0, blank = True, null = True)
medics = models.TextField('Medikamente', blank = True)
diseases = models.TextField('Krankheiten', blank = True)
comment = models.TextField('Bemerkungen', blank = True)
school = models.CharField('Schule', max_length = 75, blank = True)
date_created = models.DateTimeField('Erstellt')
date_updated = models.DateTimeField('Aktualiert')
creator = models.ForeignKey(User, verbose_name='Ersteller')
class Meta:
verbose_name = 'Spieler'
verbose_name_plural = 'Spieler'
ordering = ['lastname']
def __unicode__(self):
return '%s, %s' % (self.lastname, self.firstname)
def __str__(self):
return '%s, %s' % (self.lastname, self.firstname)
def save(self, *args, **kwargs):
if not self.id:
self.date_created = now()
self.date_updated = now()
super(Player, self).save(*args, **kwargs)
class Parent(models.Model):
firstname = models.CharField('Vorname', max_length = 20)
lastname = models.CharField('Nachname', max_length = 30)
gender = models.CharField('Geschlecht', max_length = 1, choices = [ ('M', 'Männlich'), ('W', 'Weiblich') ] )
birthday = models.DateField('Geburtstag', blank = True, null = True)
address = models.ForeignKey(Address, verbose_name = 'Adresse', related_name = 'parent_address')
phone_privat = models.CharField('Telefon Privat', max_length = 20, blank = True, null = True)
phone_handy = models.CharField('Handy', max_length = 20, blank = True, null = True)
phone_work = models.CharField('Telefon Arbeit', max_length = 20, blank = True, null = True)
email_privat = models.EmailField('Email Privat', blank = True, null = True)
email_work = models.EmailField('Email Arbeit', blank = True, null = True)
email_club = models.EmailField('Email Verein', blank = True, null = True)
is_supporter = models.BooleanField('Mitglied Förderverein', default = False)
date_supporter = models.DateField('Beitrittsdatum Förderverein', blank = True, null = True)
date_created = models.DateTimeField('Erstellt')
date_updated = models.DateTimeField('Aktualiert')
creator = models.ForeignKey(User, verbose_name='Ersteller')
class Meta:
verbose_name = 'Eltern'
verbose_name_plural = 'Eltern'
ordering = ['lastname']
def __unicode__(self):
return '%s, %s' % (self.lastname, self.firstname)
def __str__(self):
return '%s, %s' % (self.lastname, self.firstname)
def save(self, *args, **kwargs):
if not self.id:
self.date_created = now()
self.date_updated = now()
super(Parent, self).save(*args, **kwargs)
class Address(models.Model):
street = models.CharField('Straße', max_length = 50)
number = models.CharField('Nummer', max_length = 5, validators = [ RegexValidator(r'^[0-9a-z]*$', 'Keine Hausnummer') ] )
city = models.CharField('Ort', max_length = 50)
postal_code = models.CharField('PLZ', max_length = 5, validators = [ RegexValidator(r'^[1-9][0-9]*$', 'Keine Postleitzahl'), MinLengthValidator(5) ] )
class Meta:
verbose_name = 'Adresse'
verbose_name_plural = 'Adressen'
ordering = ['street']
def __unicode__(self):
return '%s %s, %s %s' % (self.street, self.number, self.postal_code, self.city)
def __str__(self):
return '%s %s, %s %s' % (self.street, self.number, self.postal_code, self.city)
class Club(models.Model):
club = models.CharField('Verein', max_length = 75)
class Meta:
verbose_name = 'Verein'
verbose_name_plural = 'Vereine'
ordering = ['club']
def __unicode__(self):
return self.club
def __str__(self):
return self.club
Naja, auch dort sind ja wieder mehrere `now()`-Abfragen drin. Wenn auch sicherlich weit unter 100.
Ich habe gelesen, der Raspi holt sich die Uhrzeit nicht von der Hardware, sondern aus dem Internet mittels NTP-Server? Stimmt das? Ich hoffe mal nicht, dass jede Abfrage der aktuellen Uhrzeit den Server befragt, oder? Das wäre irgendwie eine kranke Idee, aber wer weiß...
Ich habe gelesen, der Raspi holt sich die Uhrzeit nicht von der Hardware, sondern aus dem Internet mittels NTP-Server? Stimmt das? Ich hoffe mal nicht, dass jede Abfrage der aktuellen Uhrzeit den Server befragt, oder? Das wäre irgendwie eine kranke Idee, aber wer weiß...

Doch soweit ich weiß, holt sich der RPI die Uhrzeit von einem NTP-Server. Dies kann man aber ggf. auch ausschalten.snafu hat geschrieben:Naja, auch dort sind ja wieder mehrere `now()`-Abfragen drin. Wenn auch sicherlich weit unter 100.
Ich habe gelesen, der Raspi holt sich die Uhrzeit nicht von der Hardware, sondern aus dem Internet mittels NTP-Server? Stimmt das? Ich hoffe mal nicht, dass jede Abfrage der aktuellen Uhrzeit den Server befragt, oder? Das wäre irgendwie eine kranke Idee, aber wer weiß...
Aber ich denke, dass die Uhrzeit kein Problem sein sollte, da diese ja beim 2. Template nicht wirklich verwendet wird.
Dieses ``now()`` aus Django kommt ja von ``datetime.datetime.now()``. Mein RPi liefert 1000 Abfragen in 0.017462015152 Sekunden.
Edit:
Code: Alles auswählen
0.017462015152
root@raspberrypi:/home/pi/Python#
https://docs.djangoproject.com/en/1.7/_ ... ezone/#nowCode: Alles auswählen
def now(): """ Returns an aware or naive datetime.datetime, depending on settings.USE_TZ. """ if settings.USE_TZ: # timeit shows that datetime.now(tz=utc) is 24% slower return datetime.utcnow().replace(tzinfo=utc) else: return datetime.now()
@snafu: Der Raspi holt sich die Zeit von einem NTP-Server so wie da jeder andere Rechner auch tut: Beim starten. Ab da kümmert sich der Kernel lokal um die Uhrzeit. (Also normalerweise wird NTP regelmässig abgefragt, zum Beispiel einmal am Tag, um eventuell nachzukorrigieren, aber das ist auch auf anderen Systemen so und hat keinen Einfluss darauf wenn die Zeit in einem Programm ermittelt wird.)
@xerion21: Beim DB-Entwurf finde ich übrigens seltsam das `Player` und `Parent` *sehr* viele gemeinsame Felder haben. Das riecht komisch.
Je nach dem was damit abgebiltet werden soll ist Vater und Mutter auch ein bisschen naiv gedacht. Zumindest solange es hier nicht tatsächlich um biologische Eltern geht. Denn ansonsten will man ja beispielsweise oft eher Erziehungsberechtigte/Ansprechpartner haben. Das können zwei Väter sein, oder zwei Mütter, oder die Grosseltern, oder ein biologisches Elternteil und jemand vom Sozialamt, und auch mehr als zwei Personen.
Und bei Adressen würde ich mir fast alle Einschränkungen verkneifen. Es gibt Hausnummern die nur aus Grossbuchstaben bestehen (Haus A) oder römische Ziffern, deine Postleitzahlen können nicht mal alle gültigen, normalen deutschen Postleitzahlen abdecken weil es welche gibt die mit 0 anfangen. Es gibt auch Leute die eine Anschrift im Ausland haben. Und es gibt auch ”besondere” Adressen wie zum Beispiel Feldlager der Bundeswehr im Ausland oder Schiffe.
@xerion21: Beim DB-Entwurf finde ich übrigens seltsam das `Player` und `Parent` *sehr* viele gemeinsame Felder haben. Das riecht komisch.
Je nach dem was damit abgebiltet werden soll ist Vater und Mutter auch ein bisschen naiv gedacht. Zumindest solange es hier nicht tatsächlich um biologische Eltern geht. Denn ansonsten will man ja beispielsweise oft eher Erziehungsberechtigte/Ansprechpartner haben. Das können zwei Väter sein, oder zwei Mütter, oder die Grosseltern, oder ein biologisches Elternteil und jemand vom Sozialamt, und auch mehr als zwei Personen.
Und bei Adressen würde ich mir fast alle Einschränkungen verkneifen. Es gibt Hausnummern die nur aus Grossbuchstaben bestehen (Haus A) oder römische Ziffern, deine Postleitzahlen können nicht mal alle gültigen, normalen deutschen Postleitzahlen abdecken weil es welche gibt die mit 0 anfangen. Es gibt auch Leute die eine Anschrift im Ausland haben. Und es gibt auch ”besondere” Adressen wie zum Beispiel Feldlager der Bundeswehr im Ausland oder Schiffe.
Hier geht es wirklich nur um die biologischen Eltern erstmal. Dies wird natürlich noch erweitert.BlackJack hat geschrieben: @xerion21: Beim DB-Entwurf finde ich übrigens seltsam das `Player` und `Parent` *sehr* viele gemeinsame Felder haben. Das riecht komisch.
Je nach dem was damit abgebiltet werden soll ist Vater und Mutter auch ein bisschen naiv gedacht. Zumindest solange es hier nicht tatsächlich um biologische Eltern geht. Denn ansonsten will man ja beispielsweise oft eher Erziehungsberechtigte/Ansprechpartner haben. Das können zwei Väter sein, oder zwei Mütter, oder die Grosseltern, oder ein biologisches Elternteil und jemand vom Sozialamt, und auch mehr als zwei Personen.
Dies ist ja auch erstmal der erste Entwurf, bei dem ich mich strikt an meine Vorlage (Excel-Tabelle) gehalten hatte.
Was meinst du mit: riecht komisch?
[/quote]BlackJack hat geschrieben: Und bei Adressen würde ich mir fast alle Einschränkungen verkneifen. Es gibt Hausnummern die nur aus Grossbuchstaben bestehen (Haus A) oder römische Ziffern, deine Postleitzahlen können nicht mal alle gültigen, normalen deutschen Postleitzahlen abdecken weil es welche gibt die mit 0 anfangen. Es gibt auch Leute die eine Anschrift im Ausland haben. Und es gibt auch ”besondere” Adressen wie zum Beispiel Feldlager der Bundeswehr im Ausland oder Schiffe.
Auch hier habe ich mich erstmal an den angegeben Adressen orientiert. Das mit der PLZ habe ich erstmal nicht wirklich bedacht, sondern einfach nur an die PLZ aus meiner Umgebung gedacht, da diese Software auch nur dort eingesetzt werden soll.
Solche besonderen Adressen wie Feldlager oder so wird es nicht geben

Anschriften im Ausland werden erstmal auch nicht berücksichtigt, da dies keine Anforderung ist/war (Anforderung sind nur Adressen des lokalen Umfeldes)
@xerion21: eine falsche Validierung für Hausnummern und Postleitzahlen solltest Du trotzdem nicht haben; wo ist es überhaupt hilfreich eine Aufspaltung in Hausnummer und Straße zu haben? Macht doch nur die ganze Sache komplizierter. Wenn so viele Felder gleich sind, ist es vielleicht sinnvoll eine Personen-Tabelle zu haben und nur die Zusatzfelder in einer Player-Tabelle. Eine maximale Anzahl an Zeichen für Vor- und Nachnamen ist im Zweifel immer zu knapp. Wenn Passnummer, dann braucht man auch eine Nationalität. Oder dürfen bei Dir nur Personen mit deutscher Staatsangehörigkeit mitspielen?
@xerion21: „Riecht komisch” im Sinne von „code smell”. Das mit `Player` und `Parent` kann man so machen wenn man einen guten Grund dafür nennen kann, aber die Redundanz bei den Attributen würde man normalerweise auflösen. Mit einer Zusatztabelle in der die Gemeinsamkeiten ausgelagert werden. Die Django-Dokumentation zu „Model inheritance” ist vielleicht etwas wo man einen Blick drauf werfen könnte.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ich würde mich da langsam rantasten, um den wirklichen Flaschenhals zu finden.
z.B. mal profileing machen um zu sehen, wo die CPU Zeit verbraten wird -> https://docs.python.org/3.4/library/profile.html
Andere Möglichkeit: Nicht objects.all() sondern nur einen Eintrag nehmen.
Weiterhin: Im Template alles deaktivieren und schritt für schritt wieder aktivieren...
btw. Ich denke eine Web-Anwendung sollte ganz locker einen Request auf dem RPI in kurzer zeit ausliefert können. Ansonsten: Was für einen Webserver braucht man dann in der produktiver Umgebung, wenn wohl möglich X-fache Zugriffe zugleich erfolgen...
z.B. mal profileing machen um zu sehen, wo die CPU Zeit verbraten wird -> https://docs.python.org/3.4/library/profile.html
Andere Möglichkeit: Nicht objects.all() sondern nur einen Eintrag nehmen.
Weiterhin: Im Template alles deaktivieren und schritt für schritt wieder aktivieren...
btw. Ich denke eine Web-Anwendung sollte ganz locker einen Request auf dem RPI in kurzer zeit ausliefert können. Ansonsten: Was für einen Webserver braucht man dann in der produktiver Umgebung, wenn wohl möglich X-fache Zugriffe zugleich erfolgen...
Hallo zusammen,
sorry für meine lange Inaktivität, ich habe leider beruflich viel zu tun gehabt, und für das Projekt keine Zeit gefunden...
Ich habe nun mal herausgefunden, dass es nicht an meinem selbst erstellten Template liegt.
Selbst die "Admin-Konsole" ist genauso langsam... Egal bei was für einem View (Login/Models anzeigen/ ...).
Nun sitze ich tierisch auf dem Schlauch.
Ich werde heute abend mal die CPU Zeit mal durchchecken. mal sehn was das wird :'D
sorry für meine lange Inaktivität, ich habe leider beruflich viel zu tun gehabt, und für das Projekt keine Zeit gefunden...
Ich habe nun mal herausgefunden, dass es nicht an meinem selbst erstellten Template liegt.
Selbst die "Admin-Konsole" ist genauso langsam... Egal bei was für einem View (Login/Models anzeigen/ ...).
Nun sitze ich tierisch auf dem Schlauch.
Ich werde heute abend mal die CPU Zeit mal durchchecken. mal sehn was das wird :'D