如何对IO操作进行速率限制?

时间:2008-09-18 17:58:34

标签: algorithm language-agnostic io

假设您有一个从套接字读取的程序。如何将下载速率保持在某个给定的阈值以下?

8 个答案:

答案 0 :(得分:16)

在应用程序层(使用Berkeley套接字样式API),您只需观察时钟,以您想要限制的速率读取或写入数据。

如果你平均只读取10kbps,但是源发送的数量超过了那个,那么最终它和你之间的所有缓冲区都将填满。 TCP / IP允许这样做,并且协议将安排发送器减速(在应用层,可能所有你需要知道的是,在另一端,阻塞写入调用将阻塞,非阻塞写入将失败,并且异步写入将无法完成,直到您已阅读足够的数据才能允许它。

在应用程序层,您只能是近似值 - 您无法保证硬限制,例如“任何一秒内不超过10 kb将通过网络中的给定点”。但是如果你跟踪你收到的内容,从长远来看你可以获得平均值。

答案 1 :(得分:4)

假设网络传输是基于TCP / IP的网络传输,则响应于以另一种方式传输的ACK / NACK数据包而发送数据包。

通过限制确认收到传入数据包的数据包速率,您将反过来降低新数据包的发送速率。

它可能有点不精确,因此它可能是最佳的,以监控下游速率并自适应地调整响应速率,直到它落入舒适的阈值内。 (这会很快发生,但是你会发送一秒钟的剂量)

答案 2 :(得分:1)

如果您正在从套接字读取,则无法控制所使用的带宽 - 您正在读取该套接字的操作系统缓冲区,而您所说的任何内容都不会使写入套接字的人写入更少的数据(除非当然,你已经为此制定了协议。

所有慢慢读取的内容都是填充缓冲区,并导致网络端最终失速 - 但你无法控制这种情况发生的方式或时间。

如果你真的想一次只读取这么多数据,你可以这样做:

ReadFixedRate() {
  while(Data_Exists()) {
    t = GetTime();
    ReadBlock();
    while(t + delay > GetTime()) {
      Delay()'
    }
  }
}

答案 3 :(得分:1)

就像将游戏限制在一定数量的FPS时一样。

extern int FPS;
....    
timePerFrameinMS = 1000/FPS;

while(1) {
time = getMilliseconds();
DrawScene();
time = getMilliseconds()-time;
if (time < timePerFrameinMS) {
   sleep(timePerFrameinMS - time);
}
}

这样您就可以确保游戏刷新率最多为FPS。 以同样的方式,DrawScene可以是用于将字节泵入套接字流的函数。

答案 4 :(得分:0)

wget似乎使用--limit-rate选项来管理它。这是来自手册页:

  

请注意,Wget实现了限制   通过睡觉适量   网络阅读后的时间   比规定的时间少   率。最终这个策略会导致   TCP传输速度减慢到   大约指定的费率。   但是,可能需要一些时间   这种平衡要实现,所以不要   如果限制率,会感到惊讶   不适合很小的   文件。

答案 5 :(得分:0)

正如其他人所说,操作系统内核正在管理流量,而您只是从内核内存中读取数据的副本。要大致限制一个应用程序的速率,您需要延迟读取数据并允许传入的数据包在内核中缓冲,这最终会减慢对传入数据包的确认并降低该套接字的速率。

如果要减慢计算机的所有流量,则需要调整传入TCP缓冲区的大小。在Linux中,您可以通过更改/ proc / sys / net / ipv4 / tcp_rmem(读取内存缓冲区大小)和其他tcp_ *文件中的值来影响此更改。

答案 6 :(得分:0)

添加到Branan的答案:

如果您自愿限制接收端的读取速度,最终队列将在两端填满。然后发送方将阻塞其send()调用或从send()调用返回,其sent_length小于传递给send()调用的预期长度。

如果发件人还没准备好通过休眠处理这种情况并尝试重新发送不适合OS缓冲区的内容,那么最终会出现连接问题(发件人可能会将此检测为错误)或丢失数据(发件人可能在不知不觉中丢弃了不适合OS缓冲区的数据。)

答案 7 :(得分:0)

设置小套接字发送和接收缓冲区,比如1​​k或2k,这样带宽*延迟乘积=缓冲区大小。您可能无法通过快速链接获得足够小的内容。