Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TPL数据流反馈回路_C#_Tpl Dataflow - Fatal编程技术网

C# TPL数据流反馈回路

C# TPL数据流反馈回路,c#,tpl-dataflow,C#,Tpl Dataflow,管道获取文件的绝对路径(在块1中)并对其进行处理并将其保存到数据库(在块3中) 约束条件是某些文件类型(.vde)依赖于特定的父文件类型(.vd)。父文件类型具有处理依赖文件类型所需的元数据。除非系统中存在父文件类型,否则我无法处理从属文件类型 目标-我需要系统以某种方式等待父文件类型进入系统并更新状态。然后,将自动再次调用和处理依赖文件类型 我的方法-添加一个链接到块1的反馈循环(块4)。 然而,我最终丢失了这些消息。从block 4到block 1的消息无法到达block 3,并在管道中的某

管道获取文件的绝对路径(在
块1
中)并对其进行处理并将其保存到数据库(在
块3
中)

约束条件是某些文件类型(.vde)依赖于特定的父文件类型(.vd)。父文件类型具有处理依赖文件类型所需的元数据。除非系统中存在父文件类型,否则我无法处理从属文件类型

目标-我需要系统以某种方式等待父文件类型进入系统并更新状态。然后,将自动再次调用和处理依赖文件类型

我的方法-添加一个链接到
块1
的反馈循环(
块4
)。 然而,我最终丢失了这些消息。从
block 4
block 1
的消息无法到达
block 3
,并在管道中的某个位置丢失。

如何才能不丢失从
block 4
block 1
的消息

还是可以用更好的方式来实现


作为练习,我尝试制作一个类似于的
JoinDependencyBlock
,它从两个缓冲区传播匹配元素


更新:我提出了一个更简单的实现,在内部使用三个内置块,两个
ActionBlock
s用于输入,一个
BufferBlock
用于输出。每个动作块填充一个专用的
列表
,当添加一个元素时,两个列表将搜索匹配对。如果找到一个,则将其发布到
缓冲区块
。主要的复杂性在于这些模块的链接,因为成功和失败案例需要不同的处理

JoinDependencyBlock
完成时,内部列表中任何不匹配的元素都将被丢弃

public class JoinDependencyBlock<T1, T2> : ISourceBlock<(T1, T2)>
{
    private readonly Func<T1, T2, bool> _matchPredicate;
    private readonly List<T1> _list1 = new List<T1>();
    private readonly List<T2> _list2 = new List<T2>();
    private readonly ActionBlock<T1> _input1;
    private readonly ActionBlock<T2> _input2;
    private readonly BufferBlock<(T1, T2)> _output;
    private readonly object _locker = new object();

    public JoinDependencyBlock(Func<T1, T2, bool> matchPredicate,
        CancellationToken cancellationToken)
    {
        _matchPredicate = matchPredicate
            ?? throw new ArgumentNullException(nameof(matchPredicate));

        // Create the three internal blocks
        var options = new ExecutionDataflowBlockOptions()
        {
            CancellationToken = cancellationToken
        };
        _input1 = new ActionBlock<T1>(Add1, options);
        _input2 = new ActionBlock<T2>(Add2, options);
        _output = new BufferBlock<(T1, T2)>(options);

        // Link the input blocks with the output block
        var inputTasks = new Task[] { _input1.Completion, _input2.Completion };
        Task.WhenAny(inputTasks).Unwrap().ContinueWith(t =>
        {
            // If ANY input block fails, then the whole block has failed
            ((IDataflowBlock)_output).Fault(t.Exception.InnerException);
            if (!_input1.Completion.IsCompleted) _input1.Complete();
            if (!_input2.Completion.IsCompleted) _input2.Complete();
            ClearLists();
        }, default, TaskContinuationOptions.OnlyOnFaulted |
            TaskContinuationOptions.RunContinuationsAsynchronously,
            TaskScheduler.Default);
        Task.WhenAll(inputTasks).ContinueWith(t =>
        {
            // If ALL input blocks succeeded, then the whole block has succeeded
            _output.Complete();
            ClearLists();
        }, default, TaskContinuationOptions.NotOnFaulted |
            TaskContinuationOptions.RunContinuationsAsynchronously,
            TaskScheduler.Default);
    }

    public JoinDependencyBlock(Func<T1, T2, bool> matchPredicate)
        : this(matchPredicate, CancellationToken.None) { }

    public ITargetBlock<T1> Target1 => _input1;
    public ITargetBlock<T2> Target2 => _input2;
    public Task Completion => _output.Completion;

    private void Add1(T1 value1)
    {
        T2 value2;
        lock (_locker)
        {
            var index = _list2.FindIndex(v => _matchPredicate(value1, v));
            if (index < 0)
            {
                // Match not found
                _list1.Add(value1);
                return;
            }
            value2 = _list2[index];
            _list2.RemoveAt(index);
        }
        _output.Post((value1, value2));
    }

    private void Add2(T2 value2)
    {
        T1 value1;
        lock (_locker)
        {
            var index = _list1.FindIndex(v => _matchPredicate(v, value2));
            if (index < 0)
            {
                // Match not found
                _list2.Add(value2);
                return;
            }
            value1 = _list1[index];
            _list1.RemoveAt(index);
        }
        _output.Post((value1, value2));
    }

    private void ClearLists()
    {
        lock (_locker)
        {
            _list1.Clear();
            _list2.Clear();
        }
    }

    public void Complete() => _output.Complete();

    public void Fault(Exception exception)
        => ((IDataflowBlock)_output).Fault(exception);

    public IDisposable LinkTo(ITargetBlock<(T1, T2)> target,
        DataflowLinkOptions linkOptions)
        => _output.LinkTo(target, linkOptions);

    (T1, T2) ISourceBlock<(T1, T2)>.ConsumeMessage(
        DataflowMessageHeader messageHeader, ITargetBlock<(T1, T2)> target,
        out bool messageConsumed)
        => ((ISourceBlock<(T1, T2)>)_output).ConsumeMessage(
            messageHeader, target, out messageConsumed);

    void ISourceBlock<(T1, T2)>.ReleaseReservation(
        DataflowMessageHeader messageHeader, ITargetBlock<(T1, T2)> target)
        => ((ISourceBlock<(T1, T2)>)_output).ReleaseReservation(
            messageHeader, target);

    bool ISourceBlock<(T1, T2)>.ReserveMessage(
        DataflowMessageHeader messageHeader, ITargetBlock<(T1, T2)> target)
        => ((ISourceBlock<(T1, T2)>)_output).ReserveMessage(
            messageHeader, target);
}
公共类JoinDependencyBlock:ISourceBlock
{
私有只读函数匹配谓词;
私有只读列表_list1=新列表();
私有只读列表_list2=新列表();
私有只读操作块_input1;
私有只读操作块_input2;
专用只读缓冲块输出;
私有只读对象_locker=新对象();
公共JoinDependencyBlock(函数匹配谓词,
取消令牌(取消令牌)
{
_匹配谓词=匹配谓词
?抛出新ArgumentNullException(nameof(matchPredicate));
//创建三个内部块
var options=new ExecutionDataflowBlockOptions()
{
CancellationToken=CancellationToken
};
_input1=新操作块(添加1,选项);
_input2=新的操作块(添加2,选项);
_输出=新缓冲块(选项);
//将输入块与输出块链接
var inputasks=新任务[]{{u input1.Completion,{u input2.Completion};
Task.WhenAny(输入任务).Unwrap().ContinueWith(t=>
{
//如果任何输入块失败,则整个块都失败
((IDataflowBlock)_输出)。故障(t.Exception.InnerException);
如果(!\u input1.Completion.IsCompleted)\u input1.Complete();
如果(!\u input2.Completion.IsCompleted)\u input2.Complete();
ClearLists();
},默认值,TaskContinuationOptions.OnlyOnFaulted|
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default);
任务。当所有(输入任务)。继续(t=>
{
//如果所有输入块均成功,则整个块已成功
_output.Complete();
ClearLists();
},默认值,TaskContinuationOptions.noton故障|
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default);
}
公共JoinDependencyBlock(Func匹配谓词)
:this(matchPredicate,CancellationToken.None){}
公共ITargetBlock Target1=>\u输入1;
公共ITargetBlock Target2=>\u输入2;
公共任务完成=>\u output.Completion;
私有无效地址1(T1值1)
{
T2值2;
锁(储物柜)
{
var index=_list2.FindIndex(v=>_matchPredicate(value1,v));
如果(指数<0)
{
//找不到匹配项
_列表1.添加(值1);
返回;
}
value2=_list2[索引];
_清单2.RemoveAt(索引);
}
_输出.Post((值1,值2));
}
私人无效地址2(T2值2)
{
T1值1;
锁(储物柜)
{
var index=_list1.FindIndex(v=>_matchPredicate(v,value2));
如果(指数<0)
{
//找不到匹配项
_列表2.添加(值2);
返回;
}
value1=_list1[索引];
_列表1.删除(索引);
}
_输出.Post((值1,值2));
}
私有void ClearLists()
{
锁(储物柜)
{
_清单1.Clear();
_清单2.Clear();
}
}
public void Complete()=>_output.Complete();
公共无效错误(例外)
=>((IDataflowBlock)_输出)。故障(异常);
公共IDisposable链接到(ITargetBlock目标,
数据流链接选项(链接选项)
=>_output.LinkTo(目标,链接选项);
(T1,T2)ISourceBlock.ConsumerMessage(
DataflowMessageHeader消息头,ITargetBlock目标,
输出布尔值(已消耗)
=>((ISourceBlock)_输出)。消费消息(
messageHeader、target、out messageconsumered);
void ISourceBlock.ReleaseReservation(
DataflowMessageHeader消息头,ITargetBlock目标)
=>((ISourceBlock)_输出)。释放保留(
消息头,目标);
bool ISourceBlock.ReserveMessage(
DataflowMessageHeader消息头,ITargetBlock目标)
var joinBlock = new JoinDependencyBlock<FileInfo, FileInfo>((fi1, fi2) =>
{
    // Check if the files are matched
    var name1 = Path.GetFileNameWithoutExtension(fi1.Name);
    var name2 = Path.GetFileNameWithoutExtension(fi2.Name);
    return StringComparer.OrdinalIgnoreCase.Equals(name1, name2);
});
var actionBlock = new ActionBlock<(FileInfo, FileInfo)>(pair =>
{
    // Process the matching files
    Console.WriteLine(pair.Item1.Name + " :: " +  pair.Item2.Name);
});
joinBlock.LinkTo(actionBlock);