考虑你需要什么从收集和去那里。
下面是当你需要某种形式的集合,你应该考虑几个问题:
你需要在集合中的项随机访问?
集合是否将被多个线程访问?
读取后需要保留集合中的数据吗?
排序重要吗?如果是这样,什么顺序 - 添加订单,反向添加订单,通过一些比较项目排序?
对于在这种情况下,答案是否定的,是的,没有,是的输出缓冲器:添加顺序。这几乎挑出了ConcurrentQueue
类。这允许您添加一个或多个源代码中的对象,这些对象不需要与正在读取它们的代码位于相同的线程中。它不会让你任意索引收集(好吧,不是直接),你不需要。
我会使用相同类型的输入缓冲区,以“当前块”缓冲区来保存最近读缓冲区,包裹在一些简单的对象锁定机制,以处理任何线程的问题。
输出部分看起来是这样的:
// Output buffer
private readonly ConcurrentQueue<byte[]> _outputBuffer = new ConcurrentQueue<byte[]>();
public override void Write(byte[] buffer, int offset, int count)
{
// Copy written data to new buffer and add to output queue
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
_outputBuffer.Enqueue(data);
}
public override void Flush()
{
// pull everything out of the queue and send to wherever it is going
byte[] curr;
while (_outputBuffer.TryDequeue(out curr))
internalSendData(curr);
}
的internalSendData
方法是数据会再出去到网络。
读缓冲是稍微复杂一些:
// collection to hold unread input data
private readonly ConcurrentQueue<byte[]> _inputBuffer = new ConcurrentQueue<byte[]>();
// current data block being read from
private byte[] _inputCurrent = null;
// read offset in current block
private short _inputPos = 0;
// object for locking access to the above.
private readonly object _inputLock = new object();
public override int Read(byte[] buffer, int offset, int count)
{
int readCount = 0;
lock(_inputLock)
{
while (count > 0)
{
if (_inputCurrent == null || _inputCurrent.Length <= _inputPos)
{
// read next block from input buffer
if (!_inputBuffer.TryDequeue(out _inputCurrent))
break;
_inputPos = 0;
}
// copy bytes to destination
int nBytes = Math.Min(count, _inputCurrent.Length - _inputPos);
Buffer.BlockCopy(_inputCurrent, _inputPos, buffer, offset, nBytes);
// adjust all the offsets and counters
readCount += nBytes;
offset += nBytes;
count -= nBytes;
_inputPos += (short)nBytes;
}
}
return readCount;
}
希望这是有道理的。
使用这种软缓冲的队列意味着数据只在内存中保存,只要它们被延迟发送或读取。一旦你调用Flush
输出缓冲区的内存被释放以进行垃圾收集,所以你不必担心内存爆炸,除非你试图发送比实际传输机制更快的处理速度。但是,如果你每秒钟通过ADSL连接排队数兆字节的数据,没有什么可以为你节省:P
我想在上面添加一些改进,就像一些检查以确保一旦缓冲区处于合理的水平,即可自动调用Flush
。
'BlockingCollection'可能是一个有用的技巧。 – SimpleVar