EDIT: Es stellte sich heraus, dass es sich um einen Dill-Fehler handelt, siehe Antwort.Python: Numpy.min ersetzt Builtin: verursacht Pyro4 Fehler: Antwort-Sequenz nicht synchron
EDIT: Blick auf den Grund für meine Fortschritte bei der Problembehandlung, die durch numpy.min verursacht werden stellt sich heraus, das intern min Funktion gebaut
ich mit Pyro arbeite (Version 4.43, Python 3.5 .1, Windows 10) und versucht, einen einfachen Cluster einzurichten, in dem ein Serverprozess auf die Arbeit von Arbeitern und Arbeitsprozessen wartet und Ergebnisse sendet. Sobald der Server das Ergebnis erhält, führt er eine weitere Verarbeitung durch.
Momentan versuche ich nur, es funktioniert auf einem einzigen Computer (mit localhost und launching Worker-Prozesse vom selben Computer).
Bis jetzt kann ich den Serverprozess ausführen, und der Arbeitsprozess ist in der Lage, eine Verbindung zum Server herzustellen, um Daten anzufordern, diese Daten zu verarbeiten, aber dann verarbeitet der Worker Fehler, wenn er versucht, das Ergebnis zurückzusenden zum Server.
Ich bin in eine seltsame Fehlermeldung ausgeführt wird:
File "worker.py", line 90, in <module>
main()
File "worker.py", line 87, in main
worker.send_result()
File "worker.py", line 49, in send_result
self.server.recieve(result)
File "C:\Anaconda3\lib\site-packages\Pyro4\core.py", line 171, in __call__
return self.__send(self.__name, args, kwargs)
File "C:\Anaconda3\lib\site-packages\Pyro4\core.py", line 418, in _pyroInvoke
self.__pyroCheckSequence(msg.seq)
File "C:\Anaconda3\lib\site-packages\Pyro4\core.py", line 448, in __pyroCheckSequence
raise errors.ProtocolError(err)
Pyro4.errors.ProtocolError: invoke: reply sequence out of sync, got 0 expected 2
Nach gründlicher Suche, kann ich nur eine other person who has had this error finden, aber die Antwort war, dass dies ein reiner Pyro Fehler war, und er brauchte Pyro zu aktualisieren , aber meine Version ist weit jenseits der aktuellen, als das geschrieben wurde.
Noch weiter, ich habe Probleme, diesen Fehler außerhalb meines Produktionscodes zu reproduzieren. Ich habe versucht, eine einfache Version zu erstellen, um einzugrenzen, woher der Fehler kommt und konnte diesen Fehler nicht bekommen. Ich schickte sogar ein Ergebnis von einem Arbeiter der genauen Form des Ergebnisses, das im Produktionscode ohne Fehler gesendet wurde.
Hier ist der vereinfachte Code, nur um eine Vorstellung von der Struktur meines Setups zu geben. Dieser Code reproduziert den Fehler nicht. Ich bin mir nicht sicher, was der nächste Schritt ist, um es näher an den Produktionscode zu bringen, ohne übermäßig zu komplizieren.
Server Code:
#simple_server.py
import Pyro4
import sys, dill
class SimpleServer:
def serve(self):
with open('served data.pkl', 'rb') as f:
data = dill.load(f) #actual data coming from production code
return data
def recieve(self, result):
print(result)
def main():
Pyro4.config.SERIALIZER = 'dill' #default serpent serializer doesn't work
dill.settings['recurse'] = True #dill won't work without this option
server = SimpleServer()
daemon = Pyro4.Daemon()
server_uri = daemon.register(server)
ns = Pyro4.locateNS()
ns.register("test", server_uri)
print('Server running.')
daemon.requestLoop()
if __name__ == '__main__':
main()
Worker Code:
#simple_worker.py
import Pyro4
import sys, dill
import numpy as np
import scipy.optimize as opt
class SimpleWorker:
def __init__(self, server):
self.server = server
def recieve_data(self):
self.data = self.server.serve()
def send_result(self):
res = opt.basinhopping(lambda x: sum(x), np.arange(11), niter=2, minimizer_kwargs={'options':{'maxiter':2}})
#This below data structure is the same that I send in production
result = ('ABCD', 'filename.csv', res, 6)
self.server.recieve(result) #creates error in production code but not here
def main():
sys.excepthook = Pyro4.util.excepthook #gives a more meaningful stack trace
Pyro4.config.SERIALIZER = 'dill' #default serpent serializer doesn't work
dill.settings['recurse'] = True #dill won't work without this option
server = Pyro4.Proxy('PYRONAME:test') #connects to pinest server
worker = SimpleWorker(server)
worker.recieve_data()
worker.send_result()
if __name__ == '__main__':
main()
Windows-CMD-Code:
#run_simple_server.bat
set PYRO_SERIALIZERS_ACCEPTED=serpent,json,marshal,pickle,dill
start cmd /C python -m Pyro4.naming
python simple_server.py
pause
#run_simple_worker.bat
python simple_worker.py
pause
Hinweis: Ich brauche Dill mit der rekursiven Option zu verwenden, um diese Arten zu senden von Daten
Wenn ich Pyro4.current_context.seq
innerhalb des Worker-Hauptgeräts drucke, wird 0 zurückgegeben. Wenn ich Pyro4.current_context.seq = 2
versuche, hat dies keine Auswirkungen auf den Fehler.
Weiß jemand, wie man mit diesem Fehler umgeht oder was ich als nächstes tun sollte, um Fehler zu beheben?
EDIT: Nach einer Überprüfung der Pyro4-Quelle scheint es, dass dieser Fehler aufgrund eines Codierungsfehlers in Pyro4 ausgelöst wird. Wenn es in core.Daemon.handleRequest einen Fehler beim Empfang der Nachricht hat, setzt es seine eigene Nachrichtensequenz auf Null und versucht, den Fehler als Nachricht zu senden. Aber wenn core.Proxy._pyroInvoke empfängt die Nachricht, es hat keine Möglichkeit, es als einen Fehler zu behandeln, wenn die Sequenz Null ist. Somit wird der Fehler "Synchronisierungsfehler der Antwortsequenz" ausgelöst.
Ich habe herausgefunden, das zugrunde liegende Problem, das den Fehler beim Empfang der Nachricht verursacht. socketutil.receiveData hat eine Empfangsschleife mit einer Zeile, die das Minimum von 60000 und die verbleibende Größe der Nachricht min(60000, size - msglen)
annimmt. Irgendwie, wenn dies ausgeführt wird, verwendet es numpy.min anstelle der eingebauten Min. Und Fehler, weil das zweite Argument von numpy.min die Achsennummer sein soll. Das ist überraschend, da ich nur numpy as np
in meinen Code importiere und nie from numpy import *
oder die Min-Funktion direkt importiere.
Was noch überraschender ist, dass ich es nicht reparieren kann, indem ich es durch die eingebaute Funktion ersetze. Ich versuche import builtins
dann min = builtins.min
, und der Fehler bleibt bestehen. Wenn ich inspect.getfile(builtins.min)
ausführen, zeigt es auf die Numpy-Datei.
Ich habe versucht, das Problem vollständig zu vermeiden, indem Sie die Zeile für min([60000, size - msglen])
, die sowohl für numpy als auch für eingebaute Min funktioniert, aber die Min-Zuweisung bleibt in meinem Server Code und vermasselt Funktionen dort auch.
Als eher hackish fix, ich die obige Änderung der Min.-Funktion gehalten, sondern auch bei der Initialisierung meiner Serverklasse, speichere ich die eingebauten Funktionen:
#Store builtin functions as they later get replaced for some unknown reason
b = [t for t in().__class__.__base__.__subclasses__() if t.__name__ == 'Sized'][0].__len__.__globals__['__builtins__']
self.real_builtins = copy.copy(b) #copy so that dict doesn't get updated
Dann wird der Server jedes Mal empfängt oder sendet Daten, ich führe diese Funktion zuerst aus:
def fix_builtins(self):
global builtins
import builtins
__builtins__ = self.real_builtins
#These are all of [i for i in dir(builtins) if i in dir(numpy)]
builtins.abs = __builtins__['abs']
builtins.all = __builtins__['all']
builtins.any = __builtins__['any']
builtins.bool = __builtins__['bool']
builtins.complex = __builtins__['complex']
builtins.float = __builtins__['float']
builtins.int = __builtins__['int']
builtins.max = __builtins__['max']
builtins.min = __builtins__['min']
builtins.object = __builtins__['object']
builtins.round = __builtins__['round']
builtins.str = __builtins__['str']
builtins.sum = __builtins__['sum']
Dies scheint jetzt zu arbeiten. Aber das ist offensichtlich kein guter Weg, um das Problem zu beheben, ich würde es lieber davon abhalten, die eingebauten Funktionen zu ersetzen ... Ist das ein Pyro-spezifisches Problem?
Pyro selbst ersetzt definitiv nicht eingebaute. Wenn eine andere Bibliothek dies tut, sind alle Wetten deaktiviert. Also: was verursacht die eingebaute Minute durch numpy.min ersetzt werden? Wenn ich numpy importiere, passiert nichts Seltsames. builtins.min ist immer noch Pythons eigener eingebauter. –
@Irmen Danke für Ihre Hilfe. Warum bist du dir so sicher, dass Pyro das Problem nicht verursacht? Ich hatte den Server-Code perfekt ohne Pyro funktioniert, und sobald ich es Pyro angeschlossen habe, bekam ich das Problem. Es ist ein extrem seltsames Thema, denn selbst wenn ich 'from numpy import min' mache, ersetzt es nicht' builtins.min', nur der Name min. –
Ich meinte, dass es nichts in der Pyro-Code-Basis selbst gibt, die sich mit Builtins anlegt. Nun, was die * Serialisierer * tun, die von Pyro (pickle, dill) genannt werden, weiß ich nicht, aber vielleicht machen sie sich damit herum. Das kann immer noch erklären, warum dein Code ohne Pyro funktioniert hat, weil ich glaube, dass du die Datenstrukturen nicht durch pickle/dill weitergegeben hast. –