【发布时间】:2012-08-14 09:27:33
【问题描述】:
我正在使用BlockingCollection 来实现生产者/消费者模式。我有一个异步循环,它用要处理的数据填充集合,然后客户端可以在以后访问这些数据。数据包很少到达,我希望在不使用阻塞调用的情况下完成轮询。
本质上,我正在寻找阻塞集合中不存在的BeginTake 和EndTake 之类的东西,以便我可以在回调中使用内部线程池。无论如何,它不一定是BlockingCollection。任何能满足我需要的东西都会很棒。
这就是我现在所拥有的。 _bufferedPackets 是BlockingCollection<byte[]>:
public byte[] Read(int timeout)
{
byte[] result;
if (_bufferedPackets.IsCompleted)
{
throw new Exception("Out of packets");
}
_bufferedPackets.TryTake(out result, timeout);
return result;
}
我希望它是这样的,在伪代码中:
public void Read(int timeout)
{
_bufferedPackets.BeginTake(result =>
{
var bytes = _bufferedPackets.EndTake(result);
// Process the bytes, or the resuting timeout
}, timeout, _bufferedPackets);
}
对此我有什么选择?我不想将 任何 线程置于等待状态,因为还有很多其他 IO 内容要处理,而且我很快就会用完线程。
更新:我已经重写了相关代码,以不同方式使用异步进程,本质上是根据超时限制内是否存在等待请求来交换回调。这工作得很好,但如果有一种方法可以做到这一点,而无需求助于计时器和交换可能导致竞争条件并且难以编写(和理解)的 lambdas,它仍然会很棒。我也通过自己的异步队列实现解决了这个问题,但如果有一个更标准且经过良好测试的选项,它仍然会很棒。
【问题讨论】:
-
目前,我认为没有任何 TPL 集合向 UI 提供除 ObservableCollection 之外的异步方法。你怎么看?
-
您可以将其包装在
Task<byte[]> task = Task.Factory.StartNew<byte[]>(() => { // Your Code returning byte[] });中,但这并不明智,必须有更好的方法... -
包装一个任务将消耗一个任务,该任务将被锁定在等待句柄中。由于有许多任务正在进行,这将永远占用一个任务,这将使我不幸地用完池中的任务。
-
@Dervall 如果您担心会达到池中的最大线程数,那么我认为您的设计有问题。也许
BlockingCollection.TakeFromAny()可能有用? -
Stephen Toub 描述了在这里编写生产者/生产者队列:blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx 但我认为编写 BeginDequeue 或 DequeueAsync 将是微不足道的......
标签: c# asynchronous task-parallel-library