Python 如何同时写入多个TCP套接字?

Python 如何同时写入多个TCP套接字?,python,tcp,concurrency,Python,Tcp,Concurrency,我正在解析二进制格式的数据,并希望将生成的JSON字符串流式传输到侦听服务器。这些流是独立的,我希望每个流同时运行,以加快将数据摄取到服务器中的速度 我尝试过使用多线程库: import multiprocessing as mp def write_tcp_stream(host, port, packet): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.conn

我正在解析二进制格式的数据,并希望将生成的JSON字符串流式传输到侦听服务器。这些流是独立的,我希望每个流同时运行,以加快将数据摄取到服务器中的速度

我尝试过使用
多线程
库:

import multiprocessing as mp

def write_tcp_stream(host, port, packet):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port)) 
    except socket.error as msg:
        sys.stderr.write("[ERROR] %s\n", msg[1])
        sock.close()
        return

    sock.sendall(packet)

    sock.close()

...
p = mp.Pool(4)
for s in objects_to_stream.values() # assume s is a JSON string
    p.apply_async(write_tcp_stream, args=(HOST,PORT, s.encode())
p.close()
p.join()
但根据我正在解析的文件,我可能会出现内存不足的错误。我猜这与使用游泳池有关,但我不太了解幕后发生的事情


我认为我实际上不需要使用
多处理
,但我不知道是否可以打开多个TCP套接字并同时写入它们?我想“开火然后忘记”TCP写道。这是可能的吗?

您的问题在细节上有点轻描淡写,可以给出一个明确的答案(JSON数据包有多大?任务I/O绑定还是CPU绑定?您的所有数据都来自一个二进制文件?),但这里有一些选项可能会引导您走向正确的方向

  • 简单:将JSON写入stdout并使用netcat将其流式传输到服务器。根据数据的结构,可以启动多个实例以提高并行性

  • 非阻塞:如果您的任务是I/O绑定的,那么我将把它全部保存在一个线程中。使用户可以一次打开多个套接字并向其写入数据,但由于数据包很大,您可能需要将数据分块提供给套接字—这可能很快就会变得混乱

  • 事件框架:使用事件框架为您处理非阻塞套接字(例如,在Python3中)。这里的想法是,你有一个事件循环,它运行一个给定的协程,直到它执行一些阻塞的动作(比如说写入套接字),然后它切换到另一个协程,直到阻塞为止。如果您想自己使用非阻塞套接字,那么基本上可以实现这个功能

  • 线程:如果您的任务受CPU限制(比如通过解码二进制数据),那么最好运行多个进程来并行处理数据。线程不适用于此,因为cpythongil不允许同时运行单独的线程。使用
    多处理
    模块,或者只启动多个流程实例

  • 无论您选择哪种方法,您都应该考虑如何将数据分块处理,而不是一次将其全部加载到内存中


    如果您使用的是Python3,我建议您从
    asyncio
    开始。通过将所有内容保持在同一个线程中,您可以轻松地传递数据,并且您将获得许多开箱即用的功能。

    如果使用事件循环模型,您可以在单个线程中完成此操作。举个例子。每个
    s
    都是一个巨大的东西,如果腌制的话会变得更大吗?如果是这样的话,那么错误的意思就是它听起来的样子。如果没有,则会发生其他事情。但与此同时:您是对的,您不需要为此进行
    多处理。线程会很好,因为代码没有做任何CPU密集型工作,只是等待IO。您可以使用
    多处理.dummy.Pool
    ,或
    并发.futures.ThreadPoolExecutor
    。后者保证了您不必为了将对象作为参数传递给任务而对其进行pickle处理;它们只是在线程之间直接共享。(虽然我怀疑这不是你的实际问题…)线程可能比进程更好,如果切换修复了你的问题…那么你可以决定是否继续尝试调试多进程问题,或者只是使用线程而不必担心它。@abarnet是的,
    s
    很大,我对自己的记忆不足一点也不奇怪问题的答案。。。所有数据都来自单个二进制文件(TDMS),用于将其加载到内存中。我实际上是将每个数据点及其元数据转储到新行分隔的JSON对象中,因此在执行
    sendall()
    时,JSON字符串的长度可能超过2MB。。。