把我的头绕在TPL数据流上

本文关键字:TPL 数据流 我的 | 更新日期: 2023-09-27 18:09:51

我有一个windows服务(使用Topshelf),它承载一个WCF服务(使用SimpleInjectorServiceHost创建),并且还旋转线程(使用Task.Run)。

这个想法是:

  • WCF服务收到命令
  • 将这些命令发送到BufferBlock<T>。服务需要把这个BufferBlock<T>注入到它的构造函数
  • 线程应该是TransformBlock<T>的,它将执行所需的操作并返回结果
  • 这个结果需要被WCF服务方法读回并返回给调用者

我刚开始使用TPL数据流,所以也许我对动作块的理解是完全错误的

我在windows服务的OnStart方法中旋转线程

for(var i = 0, i < Environment.ProcessorCount, ++i)
{
    Task.Run(() =>
    {
        using (var scope = Bootstrapper.BeginScope())
        {
            var threadHost = Bootstrapper.GetInstance<IThreadHost>();
            threadHost.DoWork(_cancellationTokenSource.Token);
        }
    }, _cancellationTokenSource.Token);
};

Bootstrapper.BeginScope只是抽象了SimpleInjector的_container.BeginLifetimeScope()方法

IThreadHost/ThreadHost是一个简单的接口/类,每个命令类型都有方法。DoWork应该等待BufferBlock,并在可用时处理每个项目。

使用

启动WCF服务
if (_serviceHost != null)
{
    _serviceHost.Close();
}
_serviceHost = Bootstrapper.CreateServiceHost(typeof(NodeService));
_serviceHost.Open();

Bootstrapper.CreateServiceHost只是抽象了new SimpleInjectorServiceHost(_container, serviceType)

问:BufferBlock<T>应该是在SimpleInjector注册的单例吗?

Q:如何将每个threadHost中的DoWork设置为TransformBlock<T>并链接到BufferBlock<T> ?

问:如何在WCF服务方法中获得TransformBlock<T>的输出?WCF服务方法将命令写入BufferBlock<T>,然后需要以某种方式等待输出?

把我的头绕在TPL数据流上

我觉得你把事情弄得太复杂了。您真的不需要为TransformBlock工作线程- TPL DataFlow中的每个块已经有一个相应的任务。如果你愿意,你可以通过选项来优化它的使用。

你在这里得到的解决方案是一个通用的Producer/Consumer模式,这可以更容易地完成与TPL数据流。所以你第一个问题的答案是:

问:BufferBlock应该是在SimpleInjector中注册的单例吗?

是的,BufferBlockTransformBlock都应该是单例,但这取决于第三个问题的答案

正如我已经说过的,你真的不需要TPLTPL DataFlow的线程,所以第二个问题也很容易回答:

Q:如何将每个threadHost的DoWork设置为TransformBlock和link到BufferBlock?

您应该在您的解决方案中不使用线程,并将TransformBlock直接链接到BufferBlock

关于第三个问题,这里是有趣的部分,因为答案是:

问:如何在我的WCF服务方法中获得TransformBlock的输出?WCF服务方法将命令写入BufferBlock,然后需要以某种方式等待输出?

视情况而定。

TPL DataFlow数据处理的主要思想是它是异步的,你不能绝对确定你在TransformBlock的出口上得到的结果完全是你的请求——可能有其他数据正在被其他请求转换,简单地用OutputAvailableAsync()轮询输出可能是你的解决方案的相当低效的方法。

在这种情况下,您应该创建某种字典来处理结果,以便您可以轻松地获取信息,您的请求是否完成。在这种实现的情况下,您可以返回请求的id,并引入另一个服务方法来通过该id获取结果。

另一种方法是将数据流封装到一个助手类中,该类将包含BufferBlockTransformBlock的副本,在这种情况下,您可以使用轮询创建async方法,如链接示例中所示。请注意,在这种情况下,您实际上根本不需要TPL数据流。