Python中使用socket.send()的UDP调用非常慢

Python中使用socket.send()的UDP调用非常慢,python,linux,udp,Python,Linux,Udp,我试图在LinuxEnv中编写一个简单的Python脚本来测试一个以太网交换机,该交换机必须处理包含少量有效负载(12字节)的高频UDP消息 基本设计是我有一台笔记本电脑(带Ubuntu VirtualBox),使用socket.recvfrom()运行python脚本,连接到100Mbps交换机(Netgear FS105)。此交换机连接到一台桌面PC(带有另一个Ubuntu VirtualBox),该PC发送包含两个字节的UDP数据包。这些字节只是一个计数器,它允许我查看数据包在传输后是否被

我试图在LinuxEnv中编写一个简单的Python脚本来测试一个以太网交换机,该交换机必须处理包含少量有效负载(12字节)的高频UDP消息

基本设计是我有一台笔记本电脑(带Ubuntu VirtualBox),使用socket.recvfrom()运行python脚本,连接到100Mbps交换机(Netgear FS105)。此交换机连接到一台桌面PC(带有另一个Ubuntu VirtualBox),该PC发送包含两个字节的UDP数据包。这些字节只是一个计数器,它允许我查看数据包在传输后是否被重新排序或丢失

变速箱代码如下所示:

    self.sock = socket.socket(socket.AF_INET,
                              socket.SOCK_DGRAM) # UDP

    period_s = 1 / 5000.0 # 5KHz
    while True:
        udp_count = chr ((i >> 8) & 0xFF) + chr( i & 0xFF )
        start_time_s = time.time()
        self.sock.sendto(udp_count, (self.UDP_BROADCAST_IP, self.UDP_PORT))
        remaining_idle_time_s = period_s - start_time_s
        time.sleep(remaining_idle_time_s)
        i += 1
每几秒钟就会发生一次,剩余的空闲时间返回为负值,因为self.sock.sendto()函数花费的时间超过了0.2ms

使用cProfile,我可以看到self.sock.sendto()调用平均需要0.14毫秒,但有时需要3毫秒!使用getsockopt()我可以看到套接字发送缓冲区非常大(212992)


如何使sock.sendto()更快地返回。我猜需要3ms的情况是由于CPU决定执行另一个任务。有什么方法可以阻止我的程序进行上下文切换吗?

简单的回答是sendto()将花费多长时间,并且您不能阻止内核决定进行上下文切换以服务更高优先级的CPU中断。毕竟,操作系统就是这样做的。这就是为什么Linux,Linux

我想您可以尝试通过优化内存存储来从这块石头中榨取更多的血液,这样您通过sendto()传输的缓冲区就不会跨越页面边界,并且总是落入一些方便的缓存线中;还可以玩弄各种可调的Linux内核调度参数,从中获得一些东西

无论所有的巫毒都能取得什么成就,任何人的猜测都和其他人的一样好。也许你也可以挤出一纳秒。这些汗水和眼泪值得吗?我不知道


在我看来,如果前沿性能对您如此重要,那么您最不希望使用的就是通用操作系统,比如Linux(因为您的问题被标记为“Linux”),以及基于虚拟机的高级语言,比如Python。你会希望尽可能接近金属;这意味着C,也许更适合您的应用程序的平台将是一个专门的实时操作系统,它为应用程序提供有保证的性能。

您希望在非实时操作系统中执行实时任务(Linux不是实时操作系统)

这并不意味着要快,但要在指定的时间限制内完成任务:也就是说,防止上下文切换是一种方法,因为任务时间是可预测的

使用C或编写内核驱动程序来实现这一点可以使速度更快,但不是确定性的。有一些硬实时Linux实现,比如在虚拟机中运行它,如果您的主机不是实时的,就没有意义


在Linux中没有办法做到这一点,我对此感到非常高兴,因为阻止上下文切换的可能性意味着每个应用程序都可以阻止操作系统执行其所谓的重要任务….

好的,所以我运行了更多的测试,正如上面提到的,这种传输限制基本上受到我在Windows主机上使用Linux VirtualBox这一事实的限制

即使我将Windows中的VirtualBox进程设置为最高优先级,并在VirtualBox中设置python套接字调用RT,该进程有时仍会中断>5ms


在本机Linux机器上运行时,我可以使用
sudo chrt-r-p 99 my_python_process_id
将transmit python进程设置为实时,程序可以以10KHz的频率发送。没问题

您可能需要为Python的内存分配提供工具。(另外,如果程序如此简单,那么用C语言实现就很容易了。)