所以我有两个需要相互通信的Python3.2进程。大多数需要传达的信息都是标准字典。命名管道似乎是要走的路,所以我创建了一个可以在两个进程中实例化的管道类。这个类实现了一个非常基本的协议来获取信息。
我的问题是有时有效,有时无效。除了代码失败的地方之外,这种行为似乎没有模式。
以下是重要的 Pipe 类。如果您想要更多代码,请大声喊叫:
class Pipe:
"""
there are a bunch of constants set up here. I dont think it would be useful to include them. Just think like this: Pipe.WHATEVER = 'WHATEVER'
"""
def __init__(self,sPath):
"""
create the fifo. if it already exists just associate with it
"""
self.sPath = sPath
if not os.path.exists(sPath):
os.mkfifo(sPath)
self.iFH = os.open(sPath,os.O_RDWR | os.O_NONBLOCK)
self.iFHBlocking = os.open(sPath,os.O_RDWR)
def write(self,dMessage):
"""
write the dict to the fifo
if dMessage is not a dictionary then there will be an exception here. There never is
"""
self.writeln(Pipe.MESSAGE_START)
for k in dMessage:
self.writeln(Pipe.KEY)
self.writeln(k)
self.writeln(Pipe.VALUE)
self.writeln(dMessage[k])
self.writeln(Pipe.MESSAGE_END)
def writeln(self,s):
os.write(self.iFH,bytes('{0} : {1}\n'.format(Pipe.LINE_START,len(s)+1),'utf-8'))
os.write(self.iFH,bytes('{0}\n'.format(s), 'utf-8'))
os.write(self.iFH,bytes(Pipe.LINE_END+'\n','utf-8'))
def readln(self):
"""
look for LINE_START, get line size
read until LINE_END
clean up
return string
"""
iLineStartBaseLength = len(self.LINE_START)+3 #'{0} : '
try:
s = os.read(self.iFH,iLineStartBaseLength).decode('utf-8')
except:
return Pipe.READLINE_FAIL
if Pipe.LINE_START in s:
#get the length of the line
sLineLen = ''
while True:
try:
sCurrent = os.read(self.iFH,1).decode('utf-8')
except:
return Pipe.READLINE_FAIL
if sCurrent == '\n':
break
sLineLen += sCurrent
try:
iLineLen = int(sLineLen.strip(string.punctuation+string.whitespace))
except:
raise Exception('Not a valid line length: "{0}"'.format(sLineLen))
#read the line
sLine = os.read(self.iFHBlocking,iLineLen).decode('utf-8')
#read the line terminator
sTerm = os.read(self.iFH,len(Pipe.LINE_END+'\n')).decode('utf-8')
if sTerm == Pipe.LINE_END+'\n':
return sLine
return Pipe.READLINE_FAIL
else:
return Pipe.READLINE_FAIL
def read(self):
"""
read from the fifo, make a dict
"""
dRet = {}
sKey = ''
sValue = ''
sCurrent = None
def value_flush():
nonlocal dRet, sKey, sValue, sCurrent
if sKey:
dRet[sKey.strip()] = sValue.strip()
sKey = ''
sValue = ''
sCurrent = ''
if self.message_start():
while True:
sLine = self.readln()
if Pipe.MESSAGE_END in sLine:
value_flush()
return dRet
elif Pipe.KEY in sLine:
value_flush()
sCurrent = Pipe.KEY
elif Pipe.VALUE in sLine:
sCurrent = Pipe.VALUE
else:
if sCurrent == Pipe.VALUE:
sValue += sLine
elif sCurrent == Pipe.KEY:
sKey += sLine
else:
return Pipe.NO_MESSAGE
它有时会在这里失败(在 readln 中):
try:
iLineLen = int(sLineLen.strip(string.punctuation+string.whitespace))
except:
raise Exception('Not a valid line length: "{0}"'.format(sLineLen))
它不会在其他任何地方失败。
一个示例错误是:
Not a valid line length: "KE 17"
它间歇性的事实告诉我这是由于某种比赛条件,我只是在努力弄清楚它可能是什么。有任何想法吗?
编辑添加了有关调用进程的内容
Pipe 的使用方式是通过调用具有相同路径的构造函数在 processA 和 ProcessB 中实例化它。然后进程 A 将间歇性地写入管道,进程 B 将尝试从中读取。在任何时候,我都没有试图让这件事成为两种方式。
这是对这种情况的更冗长的解释。我一直试图让这个问题简短,但我认为现在是我放弃的时候了。Anyhoo,我有一个守护进程和一个 Pyramid 进程需要玩得很好。有两个 Pipe 实例正在使用:一个只有 Pyramid 写入,另一个只有守护进程写入。Pyramid 写的东西很短,我在这个管道上没有遇到任何错误。守护进程写的东西要长得多,这是让我伤心的管道。两个管道都以相同的方式实现。两个进程只将字典写入各自的管道(如果不是这种情况,那么 Pipe.write 中就会出现异常)。
基本算法是:Pyramid 产生守护进程,守护进程加载疯狂的厄运对象层次结构和巨大的 ram 消耗。Pyramid 将 POST 请求发送到守护进程,然后守护进程进行大量计算并将数据发送到 Pyramid,以便呈现人性化的页面。然后,人类可以通过填写 HTML 表单等来响应层次结构中的内容,从而导致金字塔向守护程序发送另一个字典,并且守护程序发送回字典响应。
所以:只有一个管道出现任何问题,问题管道的流量比另一个管道多得多,并且保证只有字典写入其中一个
编辑作为对问题和评论的回应
在你告诉我试一试之前……除了继续阅读的东西。异常被提出的事实让我感到困扰。iLineLengh = int(stuff) 在我看来应该总是传递一个看起来像整数的字符串。这种情况只是大多数时候,而不是全部。因此,如果您想评论它可能不是整数,请不要。
套用我的问题:发现比赛条件,你将成为我的英雄。
编辑一个小例子:
进程_1.py:
oP = Pipe(some_path)
while 1:
oP.write({'a':'foo','b':'bar','c':'erm...','d':'plop!','e':'etc'})
进程_2.py:
oP = Pipe(same_path_as_before)
while 1:
print(oP.read())