Ein Beispiel für Datenstreaming mit TML (The Missing Link)

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
maik_tml
User
Beiträge: 2
Registriert: Dienstag 17. Juni 2014, 12:22

Hi,

Bei der Entwicklung von Peer2Peer Netzwerken, die dazu eingerichtet werden, um große Mengen von Daten zu verarbeiten (Cluster), muss neben der Kommunikation der Knoten auch die Übertragung grosser Datenmengen sicher gestellt werden. Auch bei einfachen Anwendungen, wie (mein lieblingsbeispiel) einem Chat in dem Dateien ausgetauscht werden, sollte das verwendete Protokoll Streaming zur Verfügung stellen, um ein zweites Protokoll für die Dateiübertragung zu vermeiden.

Aus diesem Grund haben wir im TML (The Missing Link) Protokoll auch eine Streaming API implementiert. In Python kann diese mit eigenen von einer Basisklasse abgeleiteten Objekten verwendet werden.

Hier ein Beispiel für eine Funktion, die eine Datei von einem anderen Peer speichert.

Code: Alles auswählen

def save_file(self, afilename, chunksize=1024):
   sfile = open(afilename, 'wb')

   chunks = int(self.size/chunksize)+1
   assert chunks*chunksize >= self.size, "download calculation invalid"

   self.seek(0, tml.constants.SO_FROM_BEGINNING)
   for c in range(0, chunks):
       buffer = self.read(chunksize)
       sfile.write(buffer)

   sfile.close()
Eine Ausfürliche Beschreibung dieses Beispiels findet ihr hier: https://www.tml-software.com/knowledgeb ... cle/20/86/
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Schön und gut das du hier Werbung für deinen Arbeitgeber machst, aber könnte der Code nicht wesentlich schicker sein?

Es fängt schon damit an, das range(0, BLUB) identisch mit range(BLUB) ist. Int ist unnötig wenn man // verwendet und with statt close. Und warum verwendet man die Variable buffer? Dazu noch eigene Konstanten verwenden statt die Standardwerte.

SO_FROM_BEGINNING = 0
SO_FROM_CURRENT = 1
SO_FROM_END = 2
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

Was soll `sfile` bedeuten? Ich hätte ja auf `source_file` getippt, aber es scheint ja das Ziel zu sein. Das sollte man mit dem `shutil`-Modul etwas kompakter schreiben können:

Code: Alles auswählen

    def save_file(self, filename, chunksize=1024):
        with open(filename, 'wb') as target_file:
            self.seek(0, tml.constants.SO_FROM_BEGINNING)
            shutil.copyfileobj(self, target_file, chunksize)
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Name ist irgendwie unpassend. Es wird ja kein File gespeichert, sondern das Objekt in eine Datei, also entweder nur 'save' oder 'save_to_file'. Das seek scheint mir auch seltsam, wenn nicht sogar gefährlich. Bei einer Methode die etwas speichert (also eine Ausgabe-Methode), erwarte ich nicht, dass sich gleichzeitig ihr interner Zustand ändert. Also richtigerweise:

Code: Alles auswählen

    def save_file(self, filename, chunksize=1024):
        current_position = self.tell()
        self.seek(0, tml.constants.SO_FROM_BEGINNING)
        with open(filename, 'wb') as target_file:
            shutil.copyfileobj(self, target_file, chunksize)
        self.seek(current_position, tml.constants.SO_FROM_BEGINNING)
BlackJack

Da würde ich das zurücksetzen noch durch ein ``try``/``finally`` absichern:

Code: Alles auswählen

    def save_file(self, filename, chunksize=1024):
        current_position = self.tell()
        try:
            self.seek(0, tml.constants.SO_FROM_BEGINNING)
            with open(filename, 'wb') as target_file:
                shutil.copyfileobj(self, target_file, chunksize)
        finally:
            self.seek(current_position, tml.constants.SO_FROM_BEGINNING) 
Oder falls man das bei der API öfter brauchen sollte, einen Kontextmanager schreiben und ``with`` verwenden:

Code: Alles auswählen

from contextlib import contextmanager

@contextmanager
def saved_position(seekable):
    current_position = seekable.tell()
    yield seekable
    seekable.seek(current_position, tml.constants.SO_FROM_BEGINNING)

# ...

    def save_file(self, filename, chunksize=1024):
        with saved_position(self):
            self.seek(0, tml.constants.SO_FROM_BEGINNING)
            with open(filename, 'wb') as target_file:
                shutil.copyfileobj(self, target_file, chunksize)
Benutzeravatar
Pethi
User
Beiträge: 10
Registriert: Mittwoch 9. Juli 2014, 16:34

Was soll das sfile aussagen?
Grausam - heute ist mein Computer abgestürzt. Ich mußte selber denken!
Antworten