Seite 2 von 4

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 22:13
von Sirius3
BlackJack hat geschrieben:Und dann als aktuellen Wert einfach die aktuelle Anzahl von Bytes setzen.
Da ist ja das Problem ;-)

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 22:50
von BlackJack
@Sirius3: Wir brauchen dringend ein Smiley für: m) :twisted: OMG…

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 22:57
von Sophus
Inwiefern ist das ein Problem? Allerdings bin ich noch nicht weitergekommen mit dem Balken, also dass dies korrekt angezeigt wird :-)

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 23:08
von 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.

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 23:15
von Sophus
@BlackJack: Inwiefern sollten die Bytezahlen nicht stimmen?

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 23:25
von 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*.

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 23:32
von Sophus
@BlackJack: Redest du gern in Rätseln? :-) Viel geschrieben, wenig gesagt.

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_size
Ausgabe
65250090 Byte
Die Datei ist also 62,2 MB groß. Und nun nochmal, was soll daran nicht stimmen?

Re: Threading für Anfänger

Verfasst: Donnerstag 23. April 2015, 23:44
von 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.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 00:24
von Sophus
@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:

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)
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.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 00:56
von 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… :roll:

Fehlerfrei ist das immer noch nicht. Was Dir eigentlich bei Deiner Testdatei hätte auffallen müssen. Oder mit ein bisschen Nachdenken…

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 01:14
von Sophus
@BlackJack: Die Testdatei ist in Ordnung. Beim Entpacken tauchen keinerlei Fehler auf. Oder was genau soll mir da auffallen?

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 08:34
von Hyperion
Sophus 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, ...
Wieso "zu spät"? Das Beispiel rennt ja nicht weg :mrgreen:

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 09:04
von Sirius3
@Sophus: wenn Du Dir diese beiden Zeilen anschaust:

Code: Alles auswählen

               fd.write(chunk)
                downloaded_bytes += chunk_size
was ist da das naheliegendste, die Bytes, die gerade heruntergeladen wurden, zu ermitteln?

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 13:45
von Sophus
@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

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)
Hier dachte ich, könnte man die heruntergeladenen Bytes (chunk) zu den downloaded_bytes hinzuaddieren. Klappt aber nicht.

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)
Hier wollte ich nicht addieren, sondern die 'chunks' direkt benutzen.

Beide Versionen funktionieren nicht.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 14:01
von Sirius3
@Sophus: Du hast dich nicht auseinandergesetzt, sondern wild herumgeraten.

Ja requests liefert immer exakt chunk_size Bytes (und es ist unglaublich schwierig, ihm das abzugewöhnen), bis auf den letzten Chunk.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 14:07
von Sophus
@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 :-)

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 14:12
von Sirius3
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

Code: Alles auswählen

downloaded_bytes += len(chunk)
schreibt, kann es gar nicht mehr zu Abweichungen kommen. Oder noch direkter

Code: Alles auswählen

downloaded_bytes = fd.tell()
entspricht exakt der Anzahl an Bytes die geschrieben wurden.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 14:18
von Sophus
@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?

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 15:12
von Sophus
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:

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()
Jedoch sagt die QT-Dokumentation folgendes:
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.
Welche Möglich gibt es, den Vorgang sauber abzubrechen? Mit quit()-Methode habe ich auch schon versucht - klappt leider nicht.

Re: Threading für Anfänger

Verfasst: Freitag 24. April 2015, 15:40
von Hyperion
Sophus hat geschrieben: Welche Möglich gibt es, den Vorgang sauber abzubrechen? Mit quit()-Methode habe ich auch schon versucht - klappt leider nicht.
Ich verweise da noch mal auf das beste Beispiel der Welt zu diesem Thema :twisted:

Nutze eben ein Flag-Attribut, welches in der ``run``-Methode periodisch abgefragt wird. Dies kann man z.B. über eine QSemaphore machen.