我已经看过这个代码示例 - 从Stream读入缓冲区:
byte[] buffer = new byte[1024 * 32];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
//...
}
Run Code Online (Sandbox Code Playgroud)
但是看第二个参数stream.Read(..,0,..)是缓冲区中从零开始的字节偏移量,开始存储从当前流中读取的数据.
那么每次偏移是0吗?谁说它不会覆盖这些索引的数据?
恰恰相反:我也看到了这个例子:
int read, offset = 0;
while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) {
offset += read;
count -= read;
}
Run Code Online (Sandbox Code Playgroud)
所以这里的偏移量在每次读数后都会被抵消(这对我来说似乎更合乎逻辑)
但我必须遗漏一些东西:
我的观察是对的吗?我什么时候应该使用每个案例?
NB,我的pov是网络流:发送文件.
它们都是有用的代码示例,只是在不同的场景中.让我们选择你的第一个例子来添加一些代码:
Socket socket = ...;
byte[] buffer = new byte[1024 * 32];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
socket.BeginSend(buffer, 0, bytesRead , SocketFlags.None, null, null);
// Wait for completion doing something else?
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下buffer,每次重复使用,然后是,数据将被覆盖,这是预期的行为,因为你在时间读取一个块,你使用它然后继续.
你的第二个例子是相当不同的:你填充buffer与读取数据,但你不读所有的数据都在一起,你读一个较小的块每次然后offset在目标buffer必须增加.
他们有什么不同?在第一种情况下,缓冲区可以根据需要小(理想情况下甚至是一个字节),多次读取将消耗输入流.在第二种情况下,缓冲区必须足够大,以容纳您需要的所有数据.
// Note we need to know file size in advance and buffer must be big enough
// to accommodate all data we need
int read, offset = 0;
while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) {
socket.BeginSend(buffer, offset , read, SocketFlags.None, null, null);
// Here we don't need to wait BeginSend() completes.
offset += read;
count -= read;
}
Run Code Online (Sandbox Code Playgroud)
哪一个更好?很难说,如果你一次性分配所有内存,那么你很少需要通过增加块来读取块offset(只有我能想到的情况是性能优化,因为输入流上的块大小或者你想要 - 并行 - 启动在读取新数据时对接收到的数据进行一些处理).相比之下,分配一个足够容纳所有数据的缓冲区至少有两大缺点:
一般情况下(IMO)如果第一种方法(重用相同的缓冲区)在大多数情况下都相当不错,那么在大多数网络场景中,单次读取(和非阻塞发送)可能带来的性能提升可以忽略不计,而且缺点很严重.总结一下:
1 2
Unknown file size yes no
Can run out of memory yes no
Parallel processing friendly no yes
Performance optimized no yes
当然,您也可以"混合"两种方法:一个带有多个较小读取的大循环缓冲区,对于每次读取,您都会使偏移指针开始新读取并且并行处理前一个读取.有了这个,你可以从这两种方法中获益,但调整起来有点棘手(因为并发访问和可能重叠的读/写).
| 归档时间: |
|
| 查看次数: |
133 次 |
| 最近记录: |