把我的头绕在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>
,然后需要以某种方式等待输出?
我觉得你把事情弄得太复杂了。您真的不需要为TransformBlock
工作线程- TPL DataFlow中的每个块已经有一个相应的任务。如果你愿意,你可以通过选项来优化它的使用。
你在这里得到的解决方案是一个通用的Producer/Consumer
模式,这可以更容易地完成与TPL数据流。所以你第一个问题的答案是:
问:BufferBlock应该是在SimpleInjector中注册的单例吗?
是的,BufferBlock
和TransformBlock
都应该是单例,但这取决于第三个问题的答案
正如我已经说过的,你真的不需要TPL
和TPL DataFlow
的线程,所以第二个问题也很容易回答:
Q:如何将每个threadHost的DoWork设置为TransformBlock和link到BufferBlock?
您应该在您的解决方案中不使用线程,并将TransformBlock
直接链接到BufferBlock
关于第三个问题,这里是有趣的部分,因为答案是:
问:如何在我的WCF服务方法中获得TransformBlock的输出?WCF服务方法将命令写入BufferBlock,然后需要以某种方式等待输出?
视情况而定。
TPL DataFlow数据处理的主要思想是它是异步的,你不能绝对确定你在TransformBlock
的出口上得到的结果完全是你的请求——可能有其他数据正在被其他请求转换,简单地用OutputAvailableAsync()
轮询输出可能是你的解决方案的相当低效的方法。
在这种情况下,您应该创建某种字典来处理结果,以便您可以轻松地获取信息,您的请求是否完成。在这种实现的情况下,您可以返回请求的id,并引入另一个服务方法来通过该id获取结果。
另一种方法是将数据流封装到一个助手类中,该类将包含BufferBlock
和TransformBlock
的副本,在这种情况下,您可以使用轮询创建async
方法,如链接示例中所示。请注意,在这种情况下,您实际上根本不需要TPL数据流。