C# TPL数据流管道在服务内部持续运行
例如,我有三个区块:C# TPL数据流管道在服务内部持续运行,c#,task-parallel-library,.net-4.5,tpl-dataflow,C#,Task Parallel Library,.net 4.5,Tpl Dataflow,例如,我有三个区块: Buffer -> Transform -> Action 我正在运行webapi服务,它将请求中的数据带到缓冲区块。如何创建这样一个将永远运行的管道,而无需在操作块调用Completion()并停止整个管道 如果您需要在应用程序的生命周期中保留管道,而不仅仅是请求,那么您可以使用静态类来保存它。不一定需要在操作块上调用complete。根据您的需要,另一种选择是将应用程序和处理管道分开。它们可以由数据库消息队列或单独的服务器端应用程序分隔 @
Buffer -> Transform -> Action
我正在运行webapi服务,它将请求中的数据带到缓冲区块。如何创建这样一个将永远运行的管道,而无需在操作块调用Completion()并停止整个管道 如果您需要在应用程序的生命周期中保留管道,而不仅仅是请求,那么您可以使用静态类来保存它。不一定需要在操作块上调用complete。根据您的需要,另一种选择是将应用程序和处理管道分开。它们可以由数据库消息队列或单独的服务器端应用程序分隔 @svick使用TaskCompletionSource来确定管道何时完成了特定项的工作,这一点很好。总而言之,这里有一个可能有用的快速示例:
public class Controller {
public async Task<int> PostToPipeline(int inputValue) {
var message = new MessageIn(inputValue);
MyPipeline.InputBuffer.Post(message);
return await message.Completion.Task;
}
}
public class MessageIn {
public MessageIn(int value) {
InputValue = value;
Completion = new TaskCompletionSource<int>();
}
public int InputValue { get; set; }
public TaskCompletionSource<int> Completion { get; set; }
}
public class MessageProcessed {
public int ProcessedValue { get; set; }
public TaskCompletionSource<int> Completion { get; set; }
}
public static class MyPipeline {
public static BufferBlock<MessageIn> InputBuffer { get; private set; }
private static TransformBlock<MessageIn, MessageProcessed> transform;
private static ActionBlock<MessageProcessed> action;
static MyPipeline() {
BuildPipeline();
LinkPipeline();
}
static void BuildPipeline() {
InputBuffer = new BufferBlock<MessageIn>();
transform = new TransformBlock<MessageIn, MessageProcessed>((Func<MessageIn, MessageProcessed>)TransformMessage, new ExecutionDataflowBlockOptions() {
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 10
});
action = new ActionBlock<MessageProcessed>((Action<MessageProcessed>)CompletedProcessing, new ExecutionDataflowBlockOptions() {
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 10
});
}
static void LinkPipeline() {
InputBuffer.LinkTo(transform, new DataflowLinkOptions() { PropagateCompletion = true });
transform.LinkTo(action, new DataflowLinkOptions() { PropagateCompletion = true });
}
static MessageProcessed TransformMessage(MessageIn message) {
return new MessageProcessed() {
ProcessedValue = message.InputValue++,
Completion = message.Completion
};
}
static void CompletedProcessing(MessageProcessed message) {
message.Completion.SetResult(message.ProcessedValue);
}
}
公共类控制器{
公共异步任务PostToPipeline(int inputValue){
var消息=新消息输入(inputValue);
MyPipeline.InputBuffer.Post(消息);
返回等待消息.Completion.Task;
}
}
公共类消息{
公共消息输入(int值){
输入值=值;
完成=新任务完成源();
}
公共int InputValue{get;set;}
公共任务完成源完成{get;set;}
}
已处理的公共类消息{
public int ProcessedValue{get;set;}
公共任务完成源完成{get;set;}
}
公共静态类MyPipeline{
公共静态缓冲块InputBuffer{get;private set;}
私有静态块变换;
私有静态动作块动作;
静态MyPipeline(){
BuildPipeline();
链接管道();
}
静态void BuildPipeline(){
InputBuffer=新的缓冲块();
transform=new TransformBlock((Func)TransformMessage,new ExecutionDataflowBlockOptions(){
MaxDegreeOfParallelism=Environment.ProcessorCount,
边界容量=10
});
action=新建ActionBlock((action)CompletedProcessing,新建ExecutionDataflowBlockOptions(){
MaxDegreeOfParallelism=Environment.ProcessorCount,
边界容量=10
});
}
静态无效链接管道(){
LinkTo(转换,新的DataflowLinkOptions(){PropagateCompletion=true});
LinkTo(action,newdataflowlinkoptions(){PropagateCompletion=true});
}
静态消息处理转换消息(消息中的消息){
返回新的MessageProcessed(){
ProcessedValue=message.InputValue++,
完成=消息。完成
};
}
静态void CompletedProcessing(MessageProcessed消息){
message.Completion.SetResult(message.ProcessedValue);
}
}
有几种方法可以协调管道内特定工作的完成;等待完成源代码可能是满足您需求的最佳方法。对于获取特定输入的管道输出,Dataflow没有很好的解决方案(因为它支持的不仅仅是简单的管道) 要解决这个问题,您可以创建一个
TaskCompletionSource
,并将其与输入一起发送到管道。管道中的每个块将其发送到下一个块,最后一个块调用其SetResult()
然后,将输入发送到管道的代码可以等待
TaskCompletionSource
的Task
等待管道的输出。是的,我可以发送async/Post到块并在不等待完成的情况下返回,但当我真正想知道“返回的对象”时,这会导致设计问题。因此,理想情况下,我希望在不关闭所有管道的情况下实现异步完成,它必须永远等待收入,而无需重新初始化。太棒了!我的问题的漂亮解决方案。非常感谢你!