Rapide IPC/communication par Socket en Java/Python
Deux processus (Java et Python) nécessité de communiquer dans mon application. J'ai remarqué que le support de communication prend 93% du temps d'exécution. Pourquoi la communication est-elle si lente? Dois-je être à la recherche d'alternatives à la prise de communication ou cela peut-il être fait plus rapidement?
Mise à jour: j'ai découvert une solution simple. Il semble que la mémoire Tampon du flux de sortie n'est pas vraiment mis en mémoire tampon pour une raison inconnue. Donc, je vais maintenant mettre toutes les données dans la chaîne de tampons dans les deux client/serveur de processus. Je l'écris à la douille de la méthode flush.
Je suis toujours intéressé par un exemple de l'utilisation de la mémoire partagée pour échanger rapidement des données entre les processus.
Quelques informations supplémentaires:
- De taille de Message dans le formulaire est en vertu de 64 ko, la plupart du temps.
- Le serveur est en Java, le client est écrit en Python.
- Prise de la CIB est mis en œuvre ci-dessous: il faut 50 cycles de l'envoi de 200 octets ! Cela a obtenu d'être trop élevé. Si j'envoie les 2 octets de 5000 cycles, il prend beaucoup moins de temps.
- Les deux processus s'exécutent sur une machine Linux.
- Dans l'application réelle d'environ 10 appels des clients de l'iFid.write() sont effectués à chaque cycle.
- Cela se fait sur un système Linux.
C'est le côté serveur:
public class FastIPC{
public PrintWriter out;
BufferedReader in;
Socket socket = null;
ServerSocket serverSocket = null;
public FastIPC(int port) throws Exception{
serverSocket = new ServerSocket(port);
socket = serverSocket.accept();
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void send(String msg){
out.println(msg); //send price update to socket
}
public void flush(){
out.flush();
}
public String recv() throws Exception{
return in.readLine();
}
public static void main(String[] args){
int port = 32000;
try{
FastIPC fip = new FastIPC(port);
long start = new Date().getTime();
System.out.println("Connected.");
for (int i=0; i<50; i++){
for(int j=0; j<100; j++)
fip.send("+");
fip.send(".");
fip.flush();
String msg = fip.recv();
}
long stop = new Date().getTime();
System.out.println((double)(stop - start)/1000.);
}catch(Exception e){
System.exit(1);
}
}
}
Et le côté client est:
import sys
import socket
class IPC(object):
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect(("localhost", 32000))
self.fid = self.s.makefile() # file wrapper to read lines
self.listenLoop() # wait listening for updates from server
def listenLoop(self):
fid = self.fid
print "connected"
while True:
while True:
line = fid.readline()
if line[0]=='.':
break
fid.write('.\n')
fid.flush()
if __name__ == '__main__':
st = IPC()
Linux ... règlements ultérieurs de la question.
Vous avez besoin de la mémoire tampon les données. L'envoi d'octets un par un (ou dans d'autres petits morceaux) est parfaitement inefficace, peu importe si c'est l'ordinateur local ou pas.
est un tampon flux ici.
ZeroMQ serait un bon ajustement pour cela.
OriginalL'auteur fodon | 2012-02-12
Vous devez vous connecter pour publier un commentaire.
Vous avez un certain nombre d'options. Puisque vous utilisez Linux, vous pouvez utiliser les sockets de domaine UNIX. Ou, vous pourriez serialise les données au format ASCII ou JSon ou d'un autre format et l'alimentation à travers un tuyau, SHM (segment de mémoire partagée), le message de la file d'attente, DBUS ou similaire. Il vaut la peine de penser à ce genre de données que vous avez, ainsi que ces mécanismes IPC ont des caractéristiques de performance différentes. Il y a un projet de USENIX papier avec une bonne analyse des différents arbitrages qui vaut la peine de lire.
Puisque vous dites (dans les commentaires de cette réponse) que vous préférez utiliser la SHM, voici quelques exemples de code pour vous commencer. À l'aide de l'Python posix_ipc bibliothèque:
Pour le Java côté que vous souhaitez créer la même classe, en dépit de ce que j'ai dit dans les commentaires JTux semble fournir l'équivalent de la fonctionnalité et de l'API que vous avez besoin est dans UPosixIPC classe.
Le code ci-dessous est un aperçu du genre de chose que vous devez mettre en œuvre. Cependant, il ya plusieurs choses manquantes-la gestion des exceptions est le plus évident, quelques-unes des options (les trouver dans UConstant), et vous aurez envie d'ajouter dans un sémaphore à la garde du
put
/get
méthodes. Toutefois, cela devrait vous mettre sur la bonne voie. Rappelez-vous qu'unmmap
ou fichier mappé en mémoire est un fichier d'interface semblable à un segment de mémoire vive. Ainsi, vous pouvez utiliser son descripteur de fichier comme si c'était lafd
d'un fichier normal.Lire / écrire les données vers / à partir de la SHM segment dans un format que Java et en Python, il est possible de lire (ASCII, XML, ctypes, ce qui est le plus facile pour vous). Pour la partie Python vous pouvez utiliser cette bibliothèque: semanchuk.com/philip/posix_ipc pour Java il y a ceci: java.sun.com/docs/hotspot/ism.html HTH
L'ASCII est assez bon pour des raisons de simplicité. Si vous comprenez ces bien, pouvez-vous écrire un exemple simple pour que je puisse comparer les performances avec le support de la mise en œuvre dans ma question?
Aussi, je pense ISM fonctionne pour Solaris uniquement ... je m en utilisant Linux.
OK, exemple ajouté et une autre bibliothèque Java lié à...
OriginalL'auteur snim2
Quelques réflexions
Une étrange combinaison, mais est-il une raison on ne peut pas demander à l'autre de l'envoi via stdin, stdout?
Tout appel à l'OS va être relativement lente (temps de latence). En utilisant la mémoire partagée peut passer par le noyau. Si le débit est vous le problème, j'ai trouvé, vous pourrez atteindre 1 à 2 GO/s à l'aide de sockets si la latence n'est pas un problème pour vous.
Faire mémoire partagée idéal.
Ne sais pas pourquoi c'est le cas. Pourquoi ne pas créer une structure unique/tampon et de l'écrire une fois. Je voudrais utiliser un direct tampon est NIO pour minimiser les temps de latence. À l'aide de caractères de la traduction est assez cher, esp si vous avez seulement besoin ASCII.
Devrait être facile à optimiser.
Je utiliser la mémoire partagée via les fichiers mappés en mémoire. C'est parce que j'ai besoin d'enregistrer chaque message, à des fins de vérification. J'obtiens une latence moyenne d'environ 180 ns aller-retour soutenue pour des millions de messages, et à environ 490 ns dans une application réelle.
Un avantage de cette approche est que si il y a des délais courts, le lecteur peut se rattraper très rapidement avec l'écrivain. Elle soutient également les re-démarrer et la réplication facilement.
Ce n'est mise en œuvre en Java, mais le principe est assez simple et je suis sûr que ça marcherait en python.
https://github.com/peter-lawrey/Java-Chronicle
Seulement pour Java (voir mon lien) je ne sais pas python.
OriginalL'auteur Peter Lawrey