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

时间:2018-05-01 23:59:03

标签: python tcp concurrency

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

我已尝试使用multithreading库:

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

但根据我解析的文件,我可能会出现内存不足错误。我猜这与使用游泳池有关,但我不太了解幕后发生的事情。

我认为我实际上不需要使用multiprocessing,但我不知道是否可以同时打开多个TCP套接字并写入它们?我想"火与忘了" TCP写道。这可能吗?

1 个答案:

答案 0 :(得分:1)

您的问题对于细节有点明确,以给出明确的答案(JSON数据包有多大?任务I / O绑定还是CPU绑定?您的所有数据都来自一个二进制文件吗?)但这里有一些可能导致您朝着正确方向前进的选项

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

  2. 非阻止:如果您的任务是I / O绑定,那么我会将它全部保存在一个线程中。使用non-blocking sockets您可以同时打开多个套接字并向其写入数据,但是当您的数据包很大时,您可能需要将数据以块的形式提供给套接字 - 这可能很快就会变得混乱。

  3. 事件框架:使用事件框架为您处理非阻塞套接字(例如,在Python 3中为Twisted Pythonasyncio-stream)。这里的想法是你有一个事件循环运行一个给定的协同程序,直到它执行一些阻止(写入套接字说)的动作,然后它切换到另一个协同程序,直到阻止。如果您想自己使用非阻塞套接字,您基本上最终会实现此功能。

  4. 线程:如果您的任务受CPU限制(通过解码二进制数据说),那么运行多个进程并行处理数据可能是最佳的。线程不会为此工作,因为CPython GIL不允许单独的线程同时运行。使用multiprocessing模块,或只启动流程的多个实例

  5. 您选择哪种方法,您应该看看如何以块的形式处理数据,而不是一次性将其全部加载到内存中。

    如果您使用Python 3,我建议asyncio将是一个很好的起点。通过将它们保存在同一个线程中,您可以轻松传递数据,并且您可以“将获得您开箱即用的大部分功能。