gpt4 book ai didi

java - Java/Python 中的快速 IPC/Socket 通信

转载 作者:太空狗 更新时间:2023-10-29 21:29:47 24 4
gpt4 key购买 nike

两个进程(Java 和 Python)需要在我的应用程序中进行通信。我注意到套接字通信占用了 93% 的运行时间。为什么通讯这么慢?我应该寻找套接字通信的替代方法还是可以更快?

更新:我发现了一个简单的修复方法。由于某些未知原因,缓冲输出流似乎并未真正缓冲。因此,我现在将所有数据都放入客户端/服务器进程中的字符串缓冲区中。我在 flush 方法中将它写入套接字。

我仍然对使用共享内存在进程之间快速交换数据的示例感兴趣。

一些附加信息:

  1. 应用程序中的消息大小大部分时间都在 64kb 以下。
  2. 服务器用 Java 编写,客户端用 Python 编写。
  3. Socket IPC 实现如下:发送 200 个字节需要 50 个周期!这一定是太高了。如果我在 5000 个周期内发送 2 个字节,花费的时间会少很多。
  4. 两个进程都在一台 Linux 机器上运行。
  5. 在实际应用中,每个周期大约调用 10 次客户端的 iFid.write()。
  6. 这是在 Linux 系统上完成的。

这是服务器端:

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

最佳答案

您有多种选择。由于您使用的是 Linux,因此可以使用 UNIX 域套接字。或者,您可以将数据序列化为 ASCII 或 JSon 或其他格式,并通过管道、SHM(共享内存段)、消息队列、DBUS 或类似方式提供数据。值得考虑您拥有何种类型的数据,因为这些 IPC 机制具有不同的性能特征。有一个 draft USENIX paper对值得一读的各种权衡进行了很好的分析。

既然您说(在此答案的评论中)您更喜欢使用 SHM,那么这里有一些代码示例可以帮助您入门。使用 Python posix_ipc图书馆:

import posix_ipc # POSIX-specific IPC
import mmap # From Python stdlib

class SharedMemory(object):
"""Python interface to shared memory.
The create argument tells the object to create a new SHM object,
rather than attaching to an existing one.
"""

def __init__(self, name, size=posix_ipc.PAGE_SIZE, create=True):
self.name = name
self.size = size
if create:
memory = posix_ipc.SharedMemory(self.name, posix_ipc.O_CREX,
size=self.size)
else:
memory = posix_ipc.SharedMemory(self.name)
self.mapfile = mmap.mmap(memory.fd, memory.size)
os.close(memory.fd)
return

def put(self, item):
"""Put item in shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
pickle.dump(item, self.mapfile, protocol=2)
return

def get(self):
"""Get a Python object from shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
return pickle.load(self.mapfile)

def __del__(self):
try:
self.mapfile.close()
memory = posix_ipc.SharedMemory(self.name)
memory.unlink()
except:
pass
return

对于 Java 端,您想要创建相同的类,尽管我在评论中说了什么 JTux似乎提供了等效的功能,您需要的 API 在 UPosixIPC 中类。

下面的代码是您需要实现的事情的概要。但是,缺少一些东西——异常处理是显而易见的,还有一些标志(在 UConstant 中找到它们),并且您需要添加一个信号量来保护 put/get 方法。但是,这应该会让您走上正确的轨道。请记住,mmap 或内存映射文件是一段 RAM 的类文件接口(interface)。因此,您可以像使用普通文件的 fd 一样使用它的文件描述符。

import jtux.*;

class SHM {

private String name;
private int size;
private long semaphore;
private long mapfile; // File descriptor for mmap file

/* Lookup flags and perms in your system docs */
public SHM(String name, int size, boolean create, int flags, int perms) {
this.name = name;
this.size = size;
int shm;
if (create) {
flags = flags | UConstant.O_CREAT;
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
} else {
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
}
this.mapfile = UPosixIPC.mmap(..., this.size, ..., flags, shm, 0);
return;
}


public void put(String item) {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
UFile.write(item.getBytes(), this.mapfile);
return;
}


public String get() {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
byte[] buffer = new byte[this.size];
UFile.read(this.mapfile, buffer, buffer.length);
return new String(buffer);
}


public void finalize() {
UPosix.shm_unlink(this.name);
UPosix.munmap(this.mapfile, this.size);
}

}

关于java - Java/Python 中的快速 IPC/Socket 通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9250648/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com