繁体   English   中英

召唤缓慢的原因

[英]Reasons for a slow recv call

我正在编写两个应用程序(在C中),这些应用程序进行多次发送和接收调用(例如,我正在实现远程文件复制)。

我总是发送一个64字节的标题,其中包含以下消息正文的长度和一些其他信息。

在一些文件上测试我的应用程序时,我发现一些recv调用需要很长时间才能完成(大约40 毫秒 )。 使用strace我发现它首先发送一个377字节的消息体(在这种情况下它是我要复制的文件的全部内容)。

服务器应用程序开始发送消息体,大约需要48 us 现在客户端应用程序消耗大约38 毫秒来接收这些字节。

从那时起,每个接收呼叫消耗这么多时间,因为它们每个都在接收中阻塞并等待回复。

服务器的strace

[pid 27158] 1292236124.465827发送(6,“\\ 0 \\ 0 \\ 1 \\ 271 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0core.fwrite \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0“...,64,0)= 64 <0.000031>

[pid 27158] 1292236124.466074发送(6,“\\ 0 \\ 0 \\ 0 \\ 1 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 10 \\ 0 \\ 0 \\ 0 \\ 0 \\ 1 \\ \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 1 \\ 0 \\ 0 \\ 0 \\ 0“......,377,0)= 377 <0.000048>

客户的strace

[pid 27159] 1292236124.466364 recv(4,“\\ 0 \\ 0 \\ 1 \\ 271 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0core.fwrite \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0“...,64,0)= 64 <0.000027>

[pid 27159] 1292236124.466597 recv(4,“\\ 0 \\ 0 \\ 0 \\ 1 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 10 \\ 0 \\ 0 \\ 0 \\ 0 \\ 1 \\ 1 \\ \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 1 \\ 0 \\ 0 \\ 0 \\ 0“......,377,0)= 377 <0.037456>

这个问题确实给我带来了困难,因为我不明白为什么客户端上的接收呼叫花了这么多时间。

任何提示都将受到高度赞赏。

听起来像Nagle的算法对我来说。 你没有提交足够的数据,所以它会延迟一段时间,以防有更多的数据出现。 您可以通过套接字选项禁用它,然后重试。

是的,这肯定是Nagle的算法。我建议您阅读它,因为如果您发送大块数据,它应该在它有“大量”数据时立即发送。 没有自己阅读,我不完全确定“很多”是多少,但它可能是可配置的。

但是,如果您为每个连接执行一个文件,那么如果您一次性发送标题和内容,那么您应该不会遇到小文件问题 - 无论如何您应该这样做以提高吞吐量。 正如李杰所说(或多或少)“吞吐量是游戏的名称”。 您需要将文件数据与标头一起缓冲。 这是我可能会推荐多线程的少数情况之一 - 一个线程从文件填充缓冲区,另一个线程从缓冲区加载套接字。 您需要使用互斥锁保护缓冲区和关联变量,我也建议使用条件变量。 文件读取线程在添加了更多数据时发出信号,并在缓冲区已满时等待,并且套接字写入线程在读取时发出信号并在缓冲区为空时等待。 写入64字节标题后,文件读取线程不应发出信号。 让它首先加载完整的数据缓冲区。

您也可以尝试使用两个缓冲区并使用它们来减少互斥锁定延迟。 如果你做对了,文件读取线程将写入缓冲区A,而套接字写入线程正在读取缓冲区B,反之亦然,线程将更少地等待互斥锁。

即使采用这样的策略,仍然值得禁用Nagle的算法。 除了形成任何东西,如果您的代码被设计为无论如何都要避免大量的小数据包,那么Nagle的算法是多余的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM