两个进程(Java和Python)需要在我的应用程序中进行通信。我注意到套接字通信占用了93%的运行时间。为什么沟通这么慢?我应该寻找替代套接字通信的方法,还是可以更快?
更新:我发现了一个简单的修复方法。由于某种未知原因,缓冲输出流似乎没有真正缓冲。所以,我现在将所有数据放入两个客户机/服务器进程中的字符串缓冲区。我用flush方法把它写到套接字。
我仍然对使用共享内存在进程之间快速交换数据的示例感兴趣。
一些附加信息:
这是服务器端:
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);
}
}
}
客户端是:
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()
一些想法
一个奇怪的组合,但是有什么原因不能通过stdin和stdout调用另一个发送?
对操作系统的任何调用都将相对缓慢(从延迟角度看)。使用共享内存可以绕过内核。如果吞吐量是您的问题,我发现如果延迟不是您的问题,那么您可以使用套接字达到1-2 GB/s。
使共享内存成为理想。
不知道为什么会这样。为什么不构建一个单独的结构/缓冲区并写一次呢。我将使用直接缓冲区is NIO来最小化延迟。使用字符转换是相当昂贵的,特别是如果你只需要ASCII。
应该很容易优化。
我通过内存映射文件使用共享内存。这是因为我需要记录每个消息以进行审核。我得到的平均延迟约为180纳秒往返持续数百万条消息,约490纳秒在一个真正的应用程序。
这种方法的一个优点是,如果出现短暂的延迟,读者可以很快地赶上作者。它还支持轻松地重新启动和复制。
这只在Java中实现,但原理非常简单,我相信它也可以在python中工作。
https://github.com/peter-lawrey/Java-Chronicle
你有很多选择。因为您使用的是Linux,所以可以使用UNIX域套接字。或者,可以将数据序列化为ASCII或JSon或其他格式,并通过管道、SHM(共享内存段)、消息队列、dbu或类似的格式提供数据。值得考虑的是您拥有哪种类型的数据,因为这些IPC机制具有不同的性能特征。这里有一个draft USENIX paper很好地分析了各种权衡,值得一读。
既然您在对这个答案的注释中说您更喜欢使用SHM,那么下面是一些代码示例。使用Pythonposix_ipc库:
对于Java方面,您希望创建同一个类,尽管我在注释JTux中所说的似乎提供了等效的功能,而且您需要的API在UPosixIPC类中。
下面的代码概述了需要实现的类型。但是,缺少了一些东西——异常处理是显而易见的,还有一些标志(在UConstant中找到它们),您需要添加一个信号量来保护
put
/get
方法。不过,这应该会让你走上正轨。记住,mmap
或内存映射文件是RAM段的类似文件的接口。因此,可以像使用普通文件的fd
一样使用它的文件描述符。相关问题 更多 >
编程相关推荐