【问题标题】:All items in ConcurrentQueue<byte[]> are identicalConcurrentQueue<byte[]> 中的所有项目都是相同的
【发布时间】:2015-12-07 21:10:20
【问题描述】:

我有一个用于从另一个程序获取数据的 NetworkStream。数据以 Byte[64] 的形式到达,然后我将其入队到 ConcurrentQueue,以便另一个线程可以出列以便稍后进行分析。 队列被实例化:

ConcurrentQueue<byte[]> fifo = new ConcurrentQueue<byte[]>();

然后我将所有正在发送的数据排入队列:

Byte[] bytesIn = new Byte[64];
int i;
while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    fifo.Enqueue(bytesIn);
}

如果我随后查看(在调试期间)fifo 中的数据,结果发现其中包含的每个字节 [64] 都与最新的bytesIn 相同。如何确保我添加到 fifo 的数组是值而不是指针(如果这是正确的术语)?

【问题讨论】:

  • 在 C# 中使用引用类型时,您总是使用指向实际值的指针。

标签: c# concurrent-queue


【解决方案1】:

将数组的副本排入队列。您可以为此使用 ToArray 扩展名。

while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    var received = bytesIn.Take(i).ToArray();
    fifo.Enqueue(received);
}

我还使用Take 修剪缓冲区,并仅复制接收到的字节。

或者,正如 @hvd 在 cmets 中所建议的那样,使用 Array.Copy 会更快

while ((i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0)
{
    var received = new byte[i];
    Array.Copy(bytesIn, 0, received, 0, i);

    fifo.Enqueue(received);
}

【讨论】:

  • 一般来说,我会说不要为过早的优化而烦恼,但在这种情况下,我认为Take(i).ToArray() 所做的工作比需要的要多得多,它可能有一个重要的可衡量的影响,并且很容易以一种避免该问题的方式清楚地编写它:var received = new byte[i];,然后调用Array.Copy
  • 这很好,谢谢! CopyToBuffer.BlockCopy 之间有性能差异吗?
  • @zotty 没有问题。这可能会有所帮助:Array.Copy vs Buffer.BlockCopy
  • @zotty 如果您处理的数据如此之多以至于这种差异很重要,您可能不想一直分配新数组,而是使用对象池。 GC 速度很快,但也有其局限性。
【解决方案2】:

我认为这里的主要问题是您误解了将引用类型添加到您在while-loop 之外声明的队列。

如果您仔细查看您提供的代码,您会发现您只声明了一次bytesIn。您将bytesIn 排入队列,然后重写 数组的值。然而,该数组仍然是与以前相同的对象,因此不能再次排队,因此它将数组更改为新值。

那么我们真正想做的是什么?我们想要;

  • 读取流
  • 将输出放入 new 数组对象
  • 将新对象加入队列

这正是@dcastro 所做的,但我会为你精简代码;

while ((
         i = stream.Read(bytesIn, 0, bytesIn.Length)) != 0    //read the contents of the 
                                                              //stream and put it in 
                                                              //bytesIn, if available 
                                                            )
{
    var received = new byte[i];              //Create a new, empty array, which we are 
                                             //going to put in the queue.

    Array.Copy(bytesIn, 0, received, 0, i);  //Copy the contents of bytesIn into our new
                                             //array. This way we can reuse bytesIn while
                                             //maintaining the received data.

    fifo.Enqueue(received);                  //Enqueue the new array and thus saving it.
} 

如需更多信息,或许您应该阅读Reference types

【讨论】:

    猜你喜欢
    • 2017-04-03
    • 2018-09-21
    • 2021-07-09
    • 2018-12-01
    • 1970-01-01
    • 2014-11-28
    • 2016-02-09
    • 2019-10-11
    • 1970-01-01
    相关资源
    最近更新 更多