场景:有一个向客户端提供文件流的WCF流服务。在客户端,通过调用stream来读取WCF文件流。读取(buffer, 0, chunkSize),其中chunkSize为10240。
我想知道是否只有在调用Read时才通过网络(internet)传输数据,或者有一些东西在后台读取数据,并且在调用流时可能已经读取数据。读书是成功的。我问这个问题是因为我需要测量下载速度。但是,在读取数据块之后,我执行其他操作-发送事件,将数据写入只读到本地文件流。因此,我需要忽略这些其他操作,这样我就可以清楚地了解下载文件所花费的时间。因此,我一直在测量下载10KB数据所需的时间,最后kbsPerSecond是使用总文件大小和总耗时来计算的。
不幸的是,在循环中使用秒表会导致性能损失,但我想如果我想正确测量带宽,我将不得不忍受它。
long totalBytesRead = 0;
Stopwatch stopwatch = new Stopwatch();
do
{
int bytesRead;
stopwatch.Start();
bytesRead = stream.Read(buffer, 0, chunkSize);
stopwatch.Stop();
if (bytesRead == 0)
break;
totalBytesRead += bytesRead;
// 1. write to local file stream
// 2. raise file download progress events
} while (true);
long elapsedTime = stopwatch.ElapsedMilliseconds;
int kbsPerSecond = Convert.ToInt32(((double)totalBytesRead / 1024) / ((double)elapsedTime / 1000));
这种方法准确吗?
您是否测量过秒表对性能的实际影响?我刚刚在我的机器上做了一个快速测试(所以YMMV),用一个外部秒表来测量总时间,一个秒表在一个循环中模拟你正在使用的秒表。循环迭代100万次,内部秒表的总性能影响仅为49毫秒(分布在所有100万次迭代中),因此每次迭代是低个位数滴答。
除非你看到更大的影响,否则你似乎不需要担心。
我认为这种方法是相当准确的,因为你在循环中做的其他事情是非常少的。
你可以通过下载更长的流和增加chunkSize
来提高循环中有用和非有用时间的比率。同样,检查bytesRead == 0和增加totalBytesRead可能会花费很少的时间,我建议调用stopwatch。开始/停止需要更长的时间——你可以把这些调用移到循环之外
如果由于某种原因需要真正准确的读取流所需的时间(为什么需要如此高的精度尚不清楚),为什么不将读取代码完全隔离,并通过将内容读取到一个非常大的缓冲区中只调用一次(如果您知道从流中读取的内容大小,您可以使用它):
byte[] buffer = new byte[int.MaxValue]; // Alternatively, enter the size of the content
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int totalBytesRead = stream.Read(buffer, 0, buffer.Length);
stopwatch.Stop();
long elapsedTime = stopwatch.ElapsedMilliseconds;
double kbsPerSecond = ((double)totalBytesRead / 1024) / ((double)elapsedTime / 1000);
但是,如果这是生产代码,并且您正在尝试测量实际时间,那么您的方法是正确的,并且与从流中读取所花费的时间相比,创建Stop和Start方法所花费的额外时间可以忽略不计。