PyR*_*lez 6 language-agnostic concurrency multithreading network-programming
我正在制作一个程序,将下载一堆不同的项目.我的语言具有廉价的并发性,所以我首先想到我可以一次下载它们.问题是使用你没有的并发性是不好的.如果我尝试一次性下载它们,用户必须等到所有这些才能获得它们之前.
假设您正在下载10个可以以7 mb/s的速度下载的项目,并且您的下载速度为20 mb/s.该程序应该只开始下载前三项,并且只有在旧项目完成且有带宽后才开始下载新项目.另请注意,一般情况下,项目的下载速度不同.
如果我有一些程序化的方法来检查网络饱和度,这将很容易(只需检查它是否在产生新线程之前已经饱和.)
正如评论中所指出的,您不能做得足够好以做出任何保证。但是,假设你无论如何都想尽力而为。
这个问题有两个部分:
通过限制从套接字读取的速率,可以在用户空间程序中粗略地控制所消耗的带宽。TCP/IP 堆栈将通知连接的另一端,代表您的应用程序维护的队列已满,并且不会再发送任何内容。实现速率限制的一种便捷方法是使用令牌桶。
快速令牌桶实现:
int bucket = 0;
start_thread({ while(transfer_in_progress) {
bucket += bytes_per_second_limit;
sleep(1);
});
while(transfer_in_progress) {
bytesread = read(socket, buffer, min(bucket, buffersize), );
bucket -= bytesread;
}
Run Code Online (Sandbox Code Playgroud)
如果bytes_per_second_limit设置为大致可用带宽(以字节/秒表示),则读取速度应与连接允许的速度一样快。如果连接速度更快,您将受到限制bytes_per_second_limit。如果连接速度较慢,则将bucket永远增长,增长速度与速度限制和可用带宽之间的差值成正比。
唔!
如果您运行另一个线程并密切关注bucket,您可以观察两个条件:
bucket始终为 0,则有更多可用带宽,您可以增加 ,但bytes_per_second_limit可能受到您最近对可用带宽的最佳猜测(来自#2)的限制。或者开始额外下载。bucket大于您上次查看的时间,并且最后几秒的数据点似乎表明持续增长(也许可以进行线性回归;无论您喜欢什么),则以字节/秒表示的增长速率就是您可以增长的速度减少bytes_per_second_limit以使您的下载速率与可用带宽相匹配。所有这一切的问题是无法保证您的带宽保持不变。线程监控bucket可能会在增加速率和限制速率之间来回切换。我建议您在更改速率限制之前先平均至少 10 或 20 秒。