我正在开发一个允许在单台机器上模拟网络的程序。为此,我将 Twisted 用于异步 I/O,因为每个“连接”都有一个线程可能有点多。(我还使用他们的 NIO 在 Java 中实现了一个类似的程序)。然而,当我扩大模拟网络规模时,Twisted 的吞吐量会下降。将此与 Java 实现进行比较时,对于相同的网络规模,Java 吞吐量继续增长。(增长速度放缓,但仍在增长)。例如(Python 100 个节点 = 58MB 总吞吐量,300 个节点 = 45MB,Java 100 个节点 = 24 MB,300 个节点 = 56MB)。
我想知道是否有人对为什么会发生这种情况有任何建议?
我能想到的唯一原因是 Java 让每个“对等点”都在自己的线程中运行(其中包含自己的选择器,用于监视对等点的连接)。在 python 版本中,所有内容都注册到反应器(以及随后的一个选择器)。随着 python 的扩大,一个选择器无法快速响应。然而,这只是一个猜测,如果有人有任何更多的具体信息,将不胜感激。
编辑:我按照 Jean-Paul Calderone 的建议进行了一些测试,结果发布在imgur。对于那些可能想知道测试报告的以下平均吞吐量的人。(分析是用 cProfile 完成的,测试运行了 60 秒)
Epoll Reactor:100 个对等点:20.34 MB,200 个对等点:18.84 MB,300 个对等点:17.4 MB
选择 Reactor:100 个对等点:18.86 MB,200 个对等点:19.08 MB,300 个对等点:16.732 MB
报告的吞吐量似乎上下波动的几件事是对 main.py:48(send) 的调用,但这种相关性并不令人惊讶,因为这是发送数据的地方。
对于这两个反应器,套接字上的发送函数所花费的时间随着吞吐量的降低而增加,并且对发送函数的调用次数随着吞吐量的降低而减少。(即:在套接字上发送的时间更多,在套接字上发送的调用更少。)例如,在 100 个对等点上进行 413600 次调用的 epoll {method 'send' of '_socket.socket' objects} 需要 2.5 秒,达到 5.5秒用于 300 个对等点上的 epoll,用于 354300 次调用。
为了尝试回答最初的问题,这些数据是否似乎表明选择器是一个限制因素?在选择器中花费的时间似乎随着对等点数量的增加而减少(如果选择器使一切都变慢了,难道不会期望在选择器中花费的时间会增加吗?)还有什么其他可能会减慢正在发送的数据量? (数据的发送只是每一个用reactor.calllater一次又一次注册的peer的一个函数。就是main.py:49(send))