Da ist ja das ProblemBlackJack hat geschrieben:Und dann als aktuellen Wert einfach die aktuelle Anzahl von Bytes setzen.
Threading für Anfänger
-
BlackJack
@Sophus: Es ist schlicht falsch was Du da als aktuelle Byteanzahl ermittelst. Wenn die Balkenanzeige nicht stimmt wäre dass doch das erste was mal mal *selber* überprüft: Ob die Werte die man da setzt überhaupt stimmen.
-
BlackJack
@Sophus: Na die stimmen halt nicht. Wie zwei Zahlen halt nicht übereinstimmen können. Die sind nicht gleich. Also sind sie ungleich. Weil der Code nicht das aufaddiert was empfangen/gespeichert wurde. Aber so wirklich *gar nicht*.
@BlackJack: Redest du gern in Rätseln?
Viel geschrieben, wenig gesagt.
Nun, ich habe mal geschaut, und zwar:
Ausgabe
Nun, ich habe mal geschaut, und zwar:
Code: Alles auswählen
file_size = int(requests.head(self.url).headers.get('content-length', [0]))
print "%s Byte" %file_sizeDie Datei ist also 62,2 MB groß. Und nun nochmal, was soll daran nicht stimmen?65250090 Byte
-
BlackJack
@Sophus: Daran ist nichts falsch. Da wird auch nichts falsches aufaddiert. Da wird nämlich gar nichts addiert. Du hast da aber Code bei dem wird aufaddiert. Und zwar was völlig falsches. Und *das* ist auch der *Wert* der beim Fortschrittsbalken *gesetzt* wird. `file_size` dagegen wird *nicht* als *Wert* beim Fortschrittsbalken *gesetzt*. Ich spreche nicht in Rätseln sondern in Deutsch und IMHO ziemlich eindeutig. Das liegt hier am Empfänger und nicht am Sender.
@BlackJack: Wie mal mein alter Latein-Lehrer so schön sagte, wenn die Schüler nichts verstehen, dann hat der Lehrer es nicht richtig erklärt.Weise Worte
Es wäre also sehr kurzsichtig alles auf den Empfänger zu schieben. Aber egal. Kommen wir zurück zum Code. Ich habe die ganze Zeit die chunk-Größe missachtet, weil ich davon ausging, dass ich diese Größe nur brauche, damit Python weiß, in welchen Häppchen er die Bytes laden soll, damit der Arbeitsspeicher nicht in einem Rutsch vollgestopft wird. Also habe ich mir gedacht, nimmst du die Chunks dafür:
Ich denke mal, mit deinem Rätsel meintest du es so? Für mein Verständnis habe ich deshalb die Chunks-Größen genommen, weil die Bytes-Häppchen solange geladen werden, bis die Datei vollständig ist. Wenn du das nicht meinst, dann bin ich etwas überfragt.
Code: Alles auswählen
chunk_size = (8127)
downloaded_bytes = 0
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes += chunk_size
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
-
BlackJack
@Sophus: Ja das liegt wahrscheinlich an mir das Du ziemlich gezielt nichts oder etwas falsch verstehst…
Ich verstehe immer noch nicht wie man auf die Idee kommen kann das wenn man bei einer Methode `chunk_size` angibt, erwarten kann das in jedem Schleifendurchlauf `block_size` Bytes gelesen wurden, wobei `block_size` ansonsten nirgends benutzt oder bekannt gemacht wird. Das ist wohl einfach so ein supermagischer Name. Oder Python ist eine Sprache die nicht das macht was man schreibt sondern das was man meint. Also eine die Gedanken lesen kann…
Fehlerfrei ist das immer noch nicht. Was Dir eigentlich bei Deiner Testdatei hätte auffallen müssen. Oder mit ein bisschen Nachdenken…
Ich verstehe immer noch nicht wie man auf die Idee kommen kann das wenn man bei einer Methode `chunk_size` angibt, erwarten kann das in jedem Schleifendurchlauf `block_size` Bytes gelesen wurden, wobei `block_size` ansonsten nirgends benutzt oder bekannt gemacht wird. Das ist wohl einfach so ein supermagischer Name. Oder Python ist eine Sprache die nicht das macht was man schreibt sondern das was man meint. Also eine die Gedanken lesen kann…
Fehlerfrei ist das immer noch nicht. Was Dir eigentlich bei Deiner Testdatei hätte auffallen müssen. Oder mit ein bisschen Nachdenken…
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Wieso "zu spät"? Das Beispiel rennt ja nicht wegSophus hat geschrieben:Hallo Hyperion und BlackJack, danke für die Hinweise, und für das beste Beispiel der Welt, Hyperion. Aber ich habe zu spät bemerkt, dass du mir ein Beispiel präsentierst, ...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@Sophus: wenn Du Dir diese beiden Zeilen anschaust:
was ist da das naheliegendste, die Bytes, die gerade heruntergeladen wurden, zu ermitteln?
Code: Alles auswählen
fd.write(chunk)
downloaded_bytes += chunk_size@Sirius3: Meinst du etwa 'chunk'? Sprichst du hier das Problem an, was BlackJack meinte, von wegen nicht "Fehlerfrei"? Aber was spricht dagegen die chunk_size zu verwenden? Ich meine, die Häppchen werden ja solange heruntergeladen, bis die Datei komplett ist, also 100%. Und der Prozessbalken verhält sich auch "korrekt".
EDIT:
Ich habe mich mit dem 'chunk' auseinandergesetzt, udn wie zu vermuten war, hatte es auch nicht geklappt. Hier die beiden Versionen:
Version 1
Hier dachte ich, könnte man die heruntergeladenen Bytes (chunk) zu den downloaded_bytes hinzuaddieren. Klappt aber nicht.
Version 2
Hier wollte ich nicht addieren, sondern die 'chunks' direkt benutzen.
Beide Versionen funktionieren nicht.
EDIT:
Ich habe mich mit dem 'chunk' auseinandergesetzt, udn wie zu vermuten war, hatte es auch nicht geklappt. Hier die beiden Versionen:
Version 1
Code: Alles auswählen
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes += chunk
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
Version 2
Code: Alles auswählen
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
self.notify_progress_emit(chunk)
Beide Versionen funktionieren nicht.
@Sirius3: Ich komme einfach nicht dahinter, was du mir da aufzeigen willst. Der letzte 'chunk_size'-Byte ist natürlich nicht gleich groß, sondern ein Rest vom Ganzen. Aber was genau möchtest du mir mit den zwei Zeilen aufzeigen? Vielleicht eine nette Erklärung? Habe gehört, dass man dadurch auch lernen kann, und den Lernenden nicht immer alleine lässt 
Einen indirekten Wert zu nehmen, birgt immer das Risiko, dass irgendwo etwas nicht wie erwartet läuft und es deshalb zu Fehlern kommt. Wie zum Beispiel, dass der letzte Chunk kleiner und damit downloaded_bytes zu groß wird.
Wenn man also statt dessen schreibt, kann es gar nicht mehr zu Abweichungen kommen. Oder noch direkter
entspricht exakt der Anzahl an Bytes die geschrieben wurden.
Wenn man also statt dessen
Code: Alles auswählen
downloaded_bytes += len(chunk)Code: Alles auswählen
downloaded_bytes = fd.tell()@Sirius3: Danke für deine Erklärung. Und jetzt kapiere ich was du meinst. Jedoch muss ich zu meiner Schande gestehen, dass ich die Methode tell() gar nicht kannte. Und dass ich nicht selbst auf die Methode len() gekommen bin, ist mir schon etwas peinlich. Du sagtest, die tell()-Methode sei direkter. Inwiefern? Ich meine, die len()-Methode liefert genauso direkt die Größe oder?
Nun, ich möchte, dass der Anwender den Prozess des Herunterladens abbrechen kann - aus welchen Gründen auch immer. Dazu dachte ich sofort: "Nimm doch terminate()", und habe das so umgesetzt:
Jedoch sagt die QT-Dokumentation folgendes:
Code: Alles auswählen
class Download_Thread(QThread):
finished_thread = pyqtSignal()
notify_progress = pyqtSignal(int)
def __init__(self, loc, link):
QThread.__init__(self)
self.url = link
self.location = loc
def run(self):
print self.url
print self.location
file = requests.get(self.url, stream=True)
file_size = int(requests.head(self.url).headers.get('content-length', [0]))
print "%s Byte" %file_size
result = file_size / (1024*5)
print result
chunk_size = int(result)
downloaded_bytes = 0
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes = fd.tell() # sehr genau und direkt
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
print "Finish"
self.finished_thread.emit()
def stop(self):
print "Cancel"
self.finished_thread.emit()
self.terminate()Welche Möglich gibt es, den Vorgang sauber abzubrechen? Mit quit()-Methode habe ich auch schon versucht - klappt leider nicht.Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Ich verweise da noch mal auf das beste Beispiel der Welt zu diesem ThemaSophus hat geschrieben: Welche Möglich gibt es, den Vorgang sauber abzubrechen? Mit quit()-Methode habe ich auch schon versucht - klappt leider nicht.
Nutze eben ein Flag-Attribut, welches in der ``run``-Methode periodisch abgefragt wird. Dies kann man z.B. über eine QSemaphore machen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
