简体   繁体   English

如何仅使用 BroadcastBlock 和 ActionBlock 使用数据流

[英]How To Using Dataflow With Only BroadcastBlock And ActionBlock

This is my first question in SO, i'm new using DataFlow with BroadcastBlock and ActionBlock, i hope i can get solution in here.这是我在 SO 中的第一个问题,我是使用带有 BroadcastBlock 和 ActionBlock 的 DataFlow 的新手,我希望我能在这里找到解决方案。 Here's the structure.这是结构。

Model模型

class SampleModel
{
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public bool Success { get; set; } = true;
    public object UniqueData { get; set; }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine($"Id - {Id}");
        sb.AppendLine($"Success - {Success}");
        sb.AppendLine($"UniqueData - {UniqueData}");
        string tmp = sb.ToString();
        sb.Clear();
        return tmp;
    }
}

DataFlow Logic数据流逻辑

class CreateDownloadTask
{
    public async Task VeryLongProcess()
    {
        await Task.Run(async () =>
        {
            Console.WriteLine("Long Process Working..");
            await Task.Delay(TimeSpan.FromSeconds(5));
            Console.WriteLine("Long Process Done..");
        });
    }

    public async Task CreateSimpleBroadcastX<T>(T data)
    {
        Action<T> process = async model =>
        {
            Console.WriteLine("Working..");
            await VeryLongProcess();
            Console.WriteLine("Done");
        };


        var broad = new BroadcastBlock<T>(null);

        var action = new ActionBlock<T>(process);

        var dflo = new DataflowLinkOptions { PropagateCompletion = true };

        broad.LinkTo(action, dflo);

        await broad.SendAsync(data);

        broad.Complete();

        await action.Completion.ContinueWith(async tsk =>
        {
            Console.WriteLine("Continue data");
        }).ConfigureAwait(false);

        Console.WriteLine("All Done");
    }
}

Caller呼叫者

var task = cdt.CreateSimpleBroadcastX<SampleModel>(new SampleModel
{
    UniqueData = cdt.GetHashCode()
});
task.GetAwaiter().GetResult();
Console.WriteLin("Completed");

I expect the result should be我希望结果应该是

Working..
Long Process Working..
Long Process Done..
Done
Continue data
All Done
Completed

But what i've got is但我有的是

Working..
Long Process Working..
Continue data
All Done
Completed
Long Process Done..
Done

This is happen when ther is async-await inside of ActionBlock.当 ActionBlock 中有async-await时会发生这种情况。 Now, the question is, is that possible to make the result as i expected without WaitHandle ?现在,问题是,在没有WaitHandle情况下,是否有可能达到我预期的结果?

That mean, ActionBlock.Completion will be wait until the Action or Delegate inside the ActionBlock is complete executed?那就是说,ActionBlock.Completion 会一直等到 ActionBlock 中的ActionDelegate执行完毕?

Or i'm i doing it wrong with that patter?还是我用那个模式做错了?

Thanks in Advance, and sorry for my bad english.提前致谢,并为我的英语不好而感到抱歉。

Your problem is here:你的问题在这里:

Action<T> process = async model => ...

That code creates an async void method, which should be avoided .该代码创建了一个async void方法, 应该避免使用 One of the reasons you should avoid async void is because it is difficult to know when the method has completed.您应该避免async void的原因之一是因为很难知道该方法何时完成。 And this is exactly what is happening: the ActionBlock<T> cannot know when your delegate has completed because it is async void .这正是正在发生的事情: ActionBlock<T>无法知道您的委托何时完成,因为它是async void

The proper delegate type for an asynchronous method without a return value that takes a single argument is Func<T, Task> : 没有返回值且接受单个参数的异步方法的正确委托类型Func<T, Task>

Func<T, Task> process = async model => ...

Now that the asynchronous method returns a Task , the ActionBlock can know when it completes.现在异步方法返回一个TaskActionBlock可以知道它何时完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM