我想要完成的是我有MaxDegreeOfParallelism = 4
的操作块。我想为每个并行路径创建一个会话对象的本地实例,所以我想要总共4个会话对象。如果这是线程,我会创建类似的东西:
ThreadLocal<Session> sessionPerThread = new ThreadLocal<Session>(() => new Session());
我知道块不是线程所以我正在寻找类似但是块的东西。有没有办法创造这个?
此块在服务中并持续运行数月。在此期间,大量线程用于块的每个并发槽,因此线程本地存储不合适。我需要一些与逻辑块槽相关的东西。此块也永远不会完成,它会运行服务的整个生命周期。
注意:以上建议的答案对我要求的内容无效。我特别要求与本地线程不同的东西,上面的答案是使用本地线程。这完全是一个不同的问题。
答案 0 :(得分:4)
听起来您已经知道,Dataflow块绝对不能保证块,执行和线程之间的关联。即使将max parallelism设置为4,也可以在同一个线程上执行所有4个任务。或者单个任务可以在许多线程上执行。
鉴于您最终希望为 n 并行度重用昂贵服务的 n 实例,让我们将数据流完全从图片中删除一分钟,因为它不会帮助(或直接阻碍)您对此问题的任何一般解决方案。它实际上非常简单。您可以使用ConcurrentStack<T>
,其中T
是您实例化的服务类型。您的代码显示在方法(或委托)的顶部,代表您的一个并行工作单元:
private ConcurrentStack<T> reusableServices;
private void DoWork() {
T service;
if (!this.reusableServices.TryPop(out service)) {
service = new T(); // expensive construction
}
// Use your shared service.
//// Code here.
// Put the service back when we're done with it so someone else can use it.
this.reusableServices.Push(service);
}
现在通过这种方式,您可以快速地看到,您创建了与DoWork()
的并行执行一样多的昂贵服务实例。您甚至不必硬编码您期望的并行度。并且它与如何正确地实现了这种并行性(因此线程池,数据流,PLINQ等无关紧要)。
所以你可以使用DoWork()作为你的Dataflow块的委托,然后你就可以了。
当然,这里没有什么神奇的ConcurrentStack<T>
,除了push和pop周围的锁都内置在类型中,所以你不必自己动手。