我的代码总是使用包含数据库列名及其内容的Python字典,对列进行二值化(struct.pack,array.array,str.encode)并使用socket.sendall发送它们。
为了提高速度,我在生成器函数中编写了二值化部分,生成二进制块。生成器被发送到一个线程,该线程生成块并将它们放入队列中,主线程收集并发送出去。
然而,我仍然没有达到我预期的速度提升。 我想我尝试使用辅助过程而不是辅助过程。线。问题是 - 我无法将生成器传递给流程 - "不能选择"。
对于如何进行此类机制的任何建议/反馈/见解,我将不胜感激。
编辑:当使用snakeviz(cProfile with graphics)分析代码时,我看到socket.recv需要3/4的时间,而time.sleep(等待主线程中的块)需要另外1/4。那个1/4是我认为可以用另一个therad /进程缓解的,因为我读到阻塞套接字操作和time.sleep都应该释放GIL。答案 0 :(得分:1)
我不认为通过在另一个过程中执行此操作可以获得任何性能提升。生成字典的二进制表示(序列化)的功能完全是CPU绑定的 - 相对来说,应该非常快 - 而将它发送到另一个系统的功能是I / O绑定的,几乎可以肯定是更慢,最终的瓶颈。
事实上,如果将通过队列从一个线程创建的这些二进制块提供给另一个线程比在线性上下文中直接在套接字发送线程中直接运行串行器花费更多时间,我不会感到惊讶-switching和队列插入/提取/同步开销(以及GIL如果你正在使用CPython的效果)。如果将序列化移动到单独的进程,则队列发送/同步开销不太可能改变。
如果你想与其他活动同时发送 - 你担心长时间占用主线程 - 那么你应该把整个任务(序列化加上发送)委托给另一个线程或者过程
另一件需要理解的事情是,当您第一次开始发送套接字时,内核会将初始数据复制到内部缓冲区并立即将控制权返回给您 - 内核然后将数据分解为数据包并发送到协议允许异步的电线。因此,发送不会(首先)看起来是I / O绑定。但是如果要发送许多兆字节的数据,最终允许套接字的内核缓冲区空间将被填充,然后您的线程将被阻塞,直到相应的数据包被发送并被对等方确认以释放一些空间。
换句话说,在单线程实现中,如果G意味着生成一大块数据而S是socket.sendall
调用,那么在每个阶段花费的总时间将如下所示:
G|S|G|S|G|S|G|S|G|S-------|G|S------|G|S-----|G|S------ ...
首先,发送似乎接近瞬间,但过了一段时间,将开始花费更长时间才能完成。如果您没有生成足够的数据来体验这种效果,那么您更不可能将序列化推送到单独的线程。