我正在与 .Net (C++) 团队一起开发一个应用程序,并提供一个 COM 接口来与 python 和其他语言交互。
我们发现通过 COM 推送数据非常慢。
我考虑了几种替代方案:
根据您的经验,传递数据的最佳方式是什么?
在 Windows 进程间通信机制中,我们使用 windows 命名管道 获得了积极的经验。 使用 Windows 重叠 IO 和来自
pywin32的
win32pipe
模块。
您可以在《Win32 上的 Python 编程》一书中了解有关 win32 和 python 的更多信息。 发送部分只需写入
r'\\.\pipe\mypipe'
即可。
侦听器 (
ovpipe
) 对象持有事件句柄,等待可能包含其他事件的消息涉及调用
win32event.WaitForMultipleObjects
。rc = win32event.WaitForMultipleObjects(
eventlist, # Objects to wait for.
0, # Wait for one object
timeout) # timeout in milli-seconds.
这是Python重叠监听器类的一部分:
import win32event
import pywintypes
import win32file
import win32pipe
class ovpipe:
"Overlapped I/O named pipe class"
def __init__(self):
self.over=pywintypes.OVERLAPPED()
evt=win32event.CreateEvent(None,1,0,None)
self.over.hEvent=evt
self.pname='mypipe'
self.hpipe = win32pipe.CreateNamedPipe(
r'\\.\pipe\mypipe', # pipe name
win32pipe.PIPE_ACCESS_DUPLEX| # read/write access
win32file.FILE_FLAG_OVERLAPPED,
win32pipe.PIPE_TYPE_MESSAGE| # message-type pipe
win32pipe.PIPE_WAIT, # blocking mode
1, # number of instances
512, # output buffer size
512, # input buffer size
2000, # client time-out
None) # no security attributes
self.buffer = win32file.AllocateReadBuffer(512)
self.state='noconnected'
self.chstate()
def execmsg(self):
"Translate the received message"
pass
def chstate(self):
"Change the state of the pipe depending on current state"
if self.state=='noconnected':
win32pipe.ConnectNamedPipe(self.hpipe,self.over)
self.state='connectwait'
return -6
elif self.state=='connectwait':
j,self.strbuf=win32file.ReadFile(self.hpipe,self.buffer,self.over)
self.state='readwait'
return -6
elif self.state=='readwait':
size=win32file.GetOverlappedResult(self.hpipe,self.over,1)
self.msg=self.strbuf[:size]
ret=self.execmsg()
self.state = 'noconnected'
win32pipe.DisconnectNamedPipe(self.hpipe)
return ret
作为一般规则,像 COM 这样的专有协议/架构带来的限制多于其带来的好处。这就是开放规范首先出现的原因。
HTH
命名管道上的
哦,如果你这样做,我相信很多人会对结果感兴趣。
import multiprocessing
import win32event
import pywintypes
import win32file
import win32pipe
import client
class ovpipe:
"Overlapped I/O named pipe class"
def __init__(self):
self.over = pywintypes.OVERLAPPED()
evt = win32event.CreateEvent(None, 1, 0, None)
self.over.hEvent = evt
self.pname = 'mypipe'
self.hpipe = win32pipe.CreateNamedPipe(
r'\\.\pipe\mypipe', # pipe name
win32pipe.PIPE_ACCESS_DUPLEX | # read/write access
win32file.FILE_FLAG_OVERLAPPED,
win32pipe.PIPE_TYPE_MESSAGE | # message-type pipe
win32pipe.PIPE_WAIT, # blocking mode
2, # number of instances
512, # output buffer size
512, # input buffer size
2000, # client time-out
None) # no security attributes
self.buffer = win32file.AllocateReadBuffer(512)
self.state = 'noconnected'
self.chstate()
def execmsg(self):
"Translate the received message"
return bytes(self.msg).decode()
def chstate(self):
"Change the state of the pipe depending on current state"
if self.state == 'noconnected':
win32pipe.ConnectNamedPipe(self.hpipe, self.over)
self.state = 'connectwait'
return -6
elif self.state == 'connectwait':
j, self.strbuf = win32file.ReadFile(self.hpipe, self.buffer, self.over)
self.state = 'readwait'
return -6
elif self.state == 'readwait':
size = win32file.GetOverlappedResult(self.hpipe, self.over, 1)
self.msg = self.strbuf[:size]
ret = self.execmsg()
self.state = 'noconnected'
win32file.WriteFile(self.hpipe, b'Hello, client!')
win32pipe.DisconnectNamedPipe(self.hpipe)
return ret
def client_main():
PIPE_NAME = r'\\.\pipe\MyPipe'
# open a named pipe for writing
pipe = win32file.CreateFile(
PIPE_NAME,
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, # no sharing
None, # default security attributes
win32file.OPEN_EXISTING,
0, # default attributes
None # no template file
)
# send data to the server
data = b'Hello, server!'
win32file.WriteFile(pipe, data)
print(f'Sent Message to Server: \"{data.decode()}\". Waiting for response')
# receive a response from the server
response = win32file.ReadFile(pipe, 65536)
print(f'Received response from server: {response}')
# close the named pipe
win32file.CloseHandle(pipe)
def main():
ov = ovpipe()
rc = win32event.WaitForMultipleObjects(
[ov.over.hEvent], # Objects to wait for.
0, # Wait for one object
500) # timeout in milli-seconds.
print(rc)
p = multiprocessing.Process(target=client_main, daemon=True)
p.start()
for _ in range(5):
rc = win32event.WaitForMultipleObjects(
[ov.over.hEvent], # Objects to wait for.
0, # Wait for one object
2000) # timeout in milli-seconds.
print(rc)
win32event.ResetEvent(ov.over.hEvent)
if rc == 0:
res = ov.chstate()
if type(res) is str:
print(f"Received message from client: {res}")
break
p.join(10000)
if __name__ == '__main__':
main()