【问题标题】:What is the use case of ConcurrentQueue<T>.TryPeek()?ConcurrentQueue<T>.TryPeek() 的用例是什么?
【发布时间】:2014-04-02 12:08:17
【问题描述】:

受我当前问题的启发,这与此类似: Analogue of Queue.Peek() for BlockingCollection when listening to consuming IEnumerable<T> 不同的是我 - 目前 - 使用的是 ConcurrentQueue&lt;T&gt; 而不是 BlockingCollection&lt;T&gt;,我想知道 ConcurrentQueue&lt;T&gt;.TryPeek() 的任何用例可能是什么?

当然,我的意思是一个没有手动 lock(myQueue) 东西来序列化队列访问的用例,因为 TPL 旨在改进/替代这些锁定。

【问题讨论】:

  • codeguru.com/csharp/article.php/c20229/…这篇文章可能对你有所帮助。
  • 抱歉,本文与实际问题无关。意外有趣的是 ConcurrentBag 的 TryPeek() 和 TryTake() 的描述 - 但这是与 ConcurrentQueue 不同的类型

标签: c# multithreading .net-4.0 task-parallel-library


【解决方案1】:

我有一个使用ConcurrentQueue&lt;T&gt;.TryPeek 效果很好的应用程序。设置了一个线程来监控队列。主要是查看队列大小,但我们也想了解延迟。因为队列中的项目有一个时间戳字段,表示它们是什么时候放入队列的,我的监控线程可以调用TryPeek来获取队列头部的项目,从当前时间减去插入时间,并告诉我该项目在队列中的等待时间。随着时间的推移和许多样品,这让我非常清楚地了解处理收到的物品需要多长时间。

当我的监控代码仍在检查它时,其他线程可能会将该项目出列并不重要。

我可以想到其他一些场景,在这些场景中,查看队列最前面的内容会很有用,即使它可能会立即被取消。

【讨论】:

  • 是的,欣赏这种方法 - 这在我认为的完全不同的方式中是有意义的。而且我希望我自己可能从未发现过这种不同类型的用例(这就是我在这里问这个问题的原因)。另一个问题:您是如何测量队列大小的?
  • @Nicolas:队列大小由Count 属性给出。
  • 是的,好的。我之所以问是因为我实现了一个近似的内存限制 - 近似是因为我没有找到一种方法来测量没有外部工具的队列的内存大小。现在我在 en-/dequeuing 时计算每个元素的二进制序列化大小 -.- 我对替代方法感到好奇;但我希望正常数量的项目作为答案...... :)
【解决方案2】:

TryPeek 用于等待对象位于队列的第一个。 TryDequeue 将使那里的任何对象出列。因此,例如,我编写了一个多线程的网络服务器,但是在授权期间,当为某些请求启用授权时,它们需要在某一时刻按照接收到的顺序进行处理。我不想锁定整个线程函数或其中的一半,只是为了对于某些客户我可以按顺序处理他们的请求。

所以,我创建了一个Dictionary&lt;string, ConcurrentQueue&lt;HttpListenerContext&gt;&gt;,然后在服务器线程的最开始,我暂时锁定并检查是否需要授权,如果需要,我将HttpListenerContext 存储在与客户端IP 的队列中作为字典键,这样不同的客户端就不会不必要地阻塞彼此的线程。然后,我处理标头并照常计算哈希,因为页面可能会在初始之后使用 ajax 和 websockets 连接发出两个或三个请求,最好对授权信息的哈希进行多线程处理(这是我为 HttpListener 实现的摘要授权我自己,所以我不限于使用 Active Directory)。然后,当需要检查所谓的客户端 nonce 计数仅比该客户端会话的最后一次请求大一的情况时,安全功能,我使用我创建的 que 和 TryPeekThread.Yield()等到线程 HttpListenerContext 是队列中的第一个完成授权,然后将其出列。

简而言之,它可用于多线程,对于大多数线程,您希望并行运行,以利用不同的内核,但对于其中一部分线程,您需要一切都按顺序返回.

【讨论】:

    【解决方案3】:

    我有一个ConcurrentQueue,其中许多线程可能Enqueue,但我只限制一个线程执行TryPeekTryDequeue lock

    lock (dequeueLock)
        if (queue.TryPeek(out item))
            if (item.Value <= threshold)
                queue.TryDequeue(out item);
    

    注意:此代码运行时,其他线程可能会继续Enqueue

    如果有一些原子的 peek - check - dequeue 操作会更好,但lock 适合我的场景。

    【讨论】:

      【解决方案4】:

      我的理解是,当你想偷看但你不确定队列中有一个项目时,你会使用这种方法。通常在空队列上 Peek 会抛出异常。如果该项目不存在,TryPeek 将返回 false。这在多线程场景中非常有用,其中另一个线程可能会在检查空队列和实际查看值之间使项目出列。

      【讨论】:

      • 实际上 TryDequeue() 会进行这项检查,这非常酷。但是 TryPeek() 给我一个 ConcurrentQueue&lt;T&gt; 的对象在我看来是没有用的,因为不同的线程可能已经并行地将同一个对象出队。
      • 什么意思? TryPeek 返回 T 而不是 ConcurrentQueue。您是否要求一个人会 Peek 但一般不会 Dequeue 的情况(无论它是否是多线程场景)?
      • 对不起,这没有表达清楚,我的意思是:“但是 TryPeek() 给了我一个 ConcurrentQueue&lt;T&gt; 的对象 OUT ...”(当然是 T 类型) - 但在哪种情况下我现在会使用这个对象吗?我不能安全地使用它,因为它有被不同线程并行出队的危险。提醒:我对 TryPeek() 没有实际问题 - 我只是偶然发现它,不知道何时有人可以使用它,尊重所描述的情况。
      【解决方案5】:

      试试看

      T item = bc.GetConsumingEnumerable().FirstOrDefault();
      if (item != null)
      {
       //...
      }
      

      【讨论】:

      • 您能否详细说明这是如何回答问题的?
      • 在 BlockingCollection 中包装 ConcurrentQueue 允许您枚举非阻塞模式和非阻塞搜索,即: var bc = new BlockingCollection(new ConcurrentQueue() );其他线程同时继续从队列中入队 bc.TryAdd(newItem) 和 dequeue bc.TryTake(out removedItem)
      【解决方案6】:

      在取出对象之前查看对象是否有效是一种选择,请记住,当您执行此操作时,并发队列将创建一个引用,并且在您将其出列时不会从内存中释放该对象。如果您这样做了,并且您正在像我对 ConcurrentQueue 所做的那样进行内存分析,您将看到类似这样的内容。

      请注意 ConcurrentQueueSegment 有 11,060 个实例,而队列只有 8 个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-25
        • 1970-01-01
        • 1970-01-01
        • 2011-05-31
        • 1970-01-01
        相关资源
        最近更新 更多