我正在连接到一个服务器,该服务器将向我发送需要按行处理的流数据。所以我必须解析各行,然后处理每一行。以下代码似乎工作正常,但我想知道是否有任何标准的设计模式来做这种类型的事情。或者这是要走的路?
队列是否会引入任何严重的开销?我需要它尽可能快速有效,这也是我偏离像扭曲这样的图书馆的原因。
import socket, multiprocessing
def receive_proc(s, q):
data = ''
while True:
data += s.recv(4096)
if '\n' in data:
lines = data.split('\n')[:-1]
for line in lines:
if len(line) > 0:
q.put(line)
data = data.replace(line+'\n', '', 1)
q = multiprocessing.Queue()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 1234))
p = multiprocessing.Process(target=receive_proc, args=(s,q))
p.start()
while True:
line = q.get()
# do your processing here
答案 0 :(得分:4)
当然有充分的理由希望远离 twisted 之类的东西,但我认为效率不在其中 - 我怀疑他们更有可能以正确的方式进行优化。性能是一个棘手的野兽,通常瓶颈并不是你想到的,这就是为什么你需要在你可以正确优化之前进行分析。例如,框架可能已经努力将更多的代码推送到C扩展中,这肯定有助于提高性能。如果性能是您的密钥激励因素,第三方的东西可能是更安全的选择。此外,对于使用其他人已经针对各种不同用例和环境进行测试和调整的代码存在很大争议 - 如果你最终重新发明过多的轮子,那么总会存在它可能会丢失一些辐条的风险。 / p>
但是,您需要做的事情似乎很简单,因此安装和学习框架的开销以及向代码添加另一个运行时依赖性的开销可能是不合理的。此外,如果你主要是IO绑定,那么烧掉一些额外的CPU进行处理并不会产生太大的影响。我当然已经避免了过去有时会扭曲的事情,因为我知道自己编写它会更快(就我的时间而言)并且性能会“足够好”。我总是发现twisted的回调系统使得调试有点棘手 - 例如,获取错误消息可能有点令人担忧。这绝不是不可能的,许多人非常成功地使用它,但就我个人而言,我发现它太“繁琐”,无法为简单的任务辩护。
我认为在这种情况下,将接收和处理拆分为自己的进程的想法可能是错误的经济 - 从套接字接收数据非常快,如果你在纯Python中进行大量处理,那很可能是是主要的表现因素。但是,如果不知道你正在做什么处理,我不能肯定地说。如果它将耗费大量时间和/或CPU,并且您可以独立于先前的行处理每一行,那么它可能是合理的,但您可能希望将处理集中到一组工作进程。根据您现有的代码,这非常简单 - 只需将主进程设置为接收器而不是“从属”,并创建一个共享Queue
的工作池。每个工人都会经历一个循环,选择下一个项目并生成结果。无论多长时间都没关系,他们只需获得下一个项目(Queue
将为您处理)。
但是,如果您的处理循环也主要受IO限制(例如写入文件),那么您可能会发现单个进程实际上比将所有内容推送到管道上的开销要好。这取决于许多因素,包括您的CPU架构(某些系统使CPU内核之间的传输比其他系统更昂贵),但最终您不希望使用多个进程,除非您非常有信心它将为您带来性能提升。 / p>
无论如何,如果循环 IO绑定,您可能会发现一个具有非阻塞IO的进程是可行的方法。您可以使用Python的select模块自行完成此操作,或者使用eventlet或gevent等库可以更清晰。
无关 - 你从缓冲区中剥离开始的方法效率很低 - 你不需要使用replace()
就可以使用现有的split()
,如下所示:
while True:
data += s.recv(4096)
if '\n' in data:
lines = data.split('\n')
for line in lines[:-1]:
if len(line) > 0:
q.put(line)
data = lines[-1]