C# 阻止收集<;T>;。TakeFromAny,用于具有不同泛型类型的集合

C# 阻止收集<;T>;。TakeFromAny,用于具有不同泛型类型的集合,c#,generics,task-parallel-library,blockingcollection,C#,Generics,Task Parallel Library,Blockingcollection,NET中有一个方法。它首先尝试快速获取,然后默认为等待底层句柄的“慢速”方法。我想用它来听上游生产者提供“消息”和下游生产者提供“结果” TakeFromAny是否可以用于侦听对异构类型的阻塞集合集合的添加,或者是否有其他方法,而不需要重新实现 以下代码类型无效,自然无法编译: object anyValue; var collection = new List<BlockingCollection<object>>(); // following fails: ca

NET中有一个方法。它首先尝试快速获取,然后默认为等待底层句柄的“慢速”方法。我想用它来听上游生产者提供“消息”和下游生产者提供“结果”

  • TakeFromAny是否可以用于侦听对异构类型的阻塞集合集合的添加,或者是否有其他方法,而不需要重新实现
以下代码类型无效,自然无法编译:

object anyValue;
var collection = new List<BlockingCollection<object>>();
// following fails: cannot convert
//    from 'System.Collections.Concurrent.BlockingCollection<Message>'
//    to 'System.Collections.Concurrent.BlockingCollection<object>'
collection.Add(new BlockingCollection<Message>());
// fails for same reason
collection.Add(new BlockingCollection<Result>());
BlockingCollection<object>.TakeFromAny(collection.ToArray(), out anyValue);
objectanyvalue;
var collection=新列表();
//以下操作失败:无法转换
//来自“System.Collections.Concurrent.BlockingCollection”
//至“System.Collections.Concurrent.BlockingCollection”
添加(新BlockingCollection());
//因为同样的原因失败了
添加(新BlockingCollection());
BlockingCollection.TakeFromAny(collection.ToArray(),out anyValue);
可以只处理
new BlockingCollection()
实例和强制转换Take以避免编译类型错误,尽管这样会让我感觉不对劲(er)-特别是因为类型通过方法接口丢失。使用包装成分类型将解决后者;fsvo“解决”


下面没有任何内容与问题直接相关,尽管它为感兴趣的人提供了背景。提供核心基础设施功能的代码无法使用更高级别的构造(例如Rx或TPL数据流)

这是一个基本的流程模型。生产者、代理和工作线程在不同的线程上运行(工作线程可以在同一个线程上运行,具体取决于任务调度器的操作)

[producer]消息-->[proxy]消息-->[worker 1]

我认为最好的选择是将两个阻塞集合的类型都更改为
BlockingCollection
,您已经提到了这一点,包括它的缺点

如果您不能或不想这样做,另一种解决方案是为每个源集合设置一个合并的
BlockingCollection
,并为每个源集合设置一个线程,将项目从其集合移动到合并的集合:

var producerCollection = new BlockingCollection<Message>();
var consumerCollection = new BlockingCollection<Results>();

var combinedCollection = new BlockingCollection<object>();

var producerCombiner = Task.Run(() =>
{
    foreach (var item in producerCollection.GetConsumingEnumerable())
    {
        combinedCollection.Add(item);
    }
});

var consumerCombiner = Task.Run(() =>
{
    foreach (var item in consumerCollection.GetConsumingEnumerable())
    {
        combinedCollection.Add(item);
    }
});

Task.WhenAll(producerCombiner, consumerCombiner)
    .ContinueWith(_ => combinedCollection.CompleteAdding());

foreach (var item in combinedCollection.GetConsumingEnumerable())
{
    // process item here
}
var producerCollection=new BlockingCollection();
var consumerCollection=new BlockingCollection();
var combinedCollection=new BlockingCollection();
var producerCombiner=Task.Run(()=>
{
foreach(producerCollection.GetConsumingEnumerable()中的变量项)
{
合并集合。添加(项);
}
});
var consumerCombiner=Task.Run(()=>
{
foreach(consumerCollection.GetConsumingEnumerable()中的变量项)
{
合并集合。添加(项);
}
});
Task.WhenAll(生产者组合器、消费者组合器)
.ContinueWith(=>combinedCollection.CompleteAdding());
foreach(combinedCollection.GetConsumingEnumerable()中的变量项)
{
//在此处理项目
}

这不是很有效,因为它只是为了执行此操作而阻塞了两个额外的线程,但这是我所能想到的最好的替代方法,而无需使用反射来访问
TakeFromAny

1使用的句柄。可以为每个集合阻止一个线程吗?2.您是否需要保证“只从一个集合中获取”操作,或者更像是“我想处理两个集合中的所有项目,但我不想并行处理”?@s单击上游生产者(写入“消息”队列)并分散下游消费者/生产者(他们在“结果”队列中生成结果)可以被阻止-此“代理”使用者/生产者在独立于任何其他处理的线程上下文中运行,在转换后将消息从上游移动到下游使用者,并将结果作为反馈移回上游。我们的目标是“等待下一件事”,从任何队列中,完成它,然后再等待更多。@svick我想我最初的想法/设计是“使用键入的阻止集合进行轮询/选择”。@svick或“可怜人版的演员”,我决定采用
BlockingCollection
路径,具有更严格的访问权限。在这个过程中,我发现TakeFromAny是相当有偏见的。它总是倾向于第一次收集(如果它们有一个快速接收,或者如果多个等待句柄同时发出信号,则是慢速接收)。