TPL Dataflow如何与“全局”数据同步

时间:2017-06-06 05:01:01

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

我实际上是在学习TPL数据流。每当我读到它的某些内容时,我认为好听起来很棒,但后来我经常问自己:“好的,如果我有一个经理,处理不同的会话会怎么样。这些会话可以通过某些消息更新。如果是复杂的TPL数据流网格我要内置用于访问管理器的同步机制,这将减慢或阻塞网格。“

使用TPL数据流的管理对象感觉有点不对劲。

任何人都可以给我一些提示(链接,书籍,例子......)到“正确”的方向,如何解决上面的例子。

1 个答案:

答案 0 :(得分:2)

没有一些代码的那种非常广泛的问题。但通常你要么传递一些带有Tuple的“状态”对象或一些DTO,我个人认为它是泄漏设计,或者你可以在管道中注入一些块。

例如,您可以创建一个WriteOnceBlock,为其提供一个会话值,每个管道都是唯一的,并且只是通过执行期间发生的新事件通知它的值。如果您为不同的会话创建管道,这可能是一个选项,但如果您有一个大管道,则需要另一种方式。

例如,您有一个BufferBlock,一个ActionBlock执行会话更新,还有一个TransformBlock,它只是继续正常的管道执行。在这种情况下你可以做的是引入一个BroadcastBlock,将它与动作块和变换块链接起来。现在,您将缓冲区链接到带有谓词的广播块,然后将缓冲区链接到直接转换块。

这里的想法是,如果您的消息被过滤(因此需要更新会话),它将转到广播块,然后转到会话更新操作和正常执行管道。如果它与谓词不匹配,它只会超越您的正常工作流程。

PS:如果这句话过于复杂,我可以为这种情况提供一些示例代码。

var linkOptions = new DataflowLinkOptions { PropagateCompletion = true };

var buffer = new BufferBlock<int>();
// broadcast do copy according lambda from constructor
// if you provide same reference for message, make sure that your access is thread-safe
var broadcast = new BroadcastBlock<int>(i => i);
buffer.LinkTo(broadcast, linkOptions);

// session update block
var sessionUpdate = new ActionBlock<int>(i =>
    {
        Thread.Sleep(new Random().Next(1000));
        Console.WriteLine($"Session update:{i}");
    }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });
// normal execution
var transform = new TransformBlock<int, int>(i =>
    {
        Thread.Sleep(new Random().Next(1000));
        Console.WriteLine($"Normal execution:{i}");
        return i;
    }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });
// do not complete the standalone session block
// message will be accepted only for multipliers of 3
broadcast.LinkTo(sessionUpdate, i => i % 3 == 0);
// normal pipeline with completion propagation
broadcast.LinkTo(transform, linkOptions);

for (var i = 0; i < 10; ++i)
{
    // async message
    await buffer.SendAsync(i);
}
buffer.Complete();
await transform.Completion;