TPL Dataflow本地存储或类似的东西

时间:2013-03-07 07:47:59

标签: c# task-parallel-library tpl-dataflow

我想要完成的是我有MaxDegreeOfParallelism = 4的操作块。我想为每个并行路径创建一个会话对象的本地实例,所以我想要总共4个会话对象。如果这是线程,我会创建类似的东西:

 ThreadLocal<Session> sessionPerThread = new ThreadLocal<Session>(() => new Session());

我知道块不是线程所以我正在寻找类似但是块的东西。有没有办法创造这个?

此块在服务中并持续运行数月。在此期间,大量线程用于块的每个并发槽,因此线程本地存储不合适。我需要一些与逻辑块槽相关的东西。此块也永远不会完成,它会运行服务的整个生命周期。

注意:以上建议的答案对我要求的内容无效。我特别要求与本地线程不同的东西,上面的答案是使用本地线程。这完全是一个不同的问题。

1 个答案:

答案 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周围的锁都内置在类型中,所以你不必自己动手。