依次运行动态添加的任务

huangapple go评论116阅读模式
英文:

Run dynamically added tasks one after one

问题

Application (wpf, .net framework 4.8) 可以从外部(rpc、ui 等)接收一些命令,而且可以接收得比可以执行得更快。在命令与硬件一起工作时,我希望它们按顺序执行。
我正在寻找想法,因为我甚至不确定我的计划是否能够奏效。

我目前的想法是以某种方式使用 Dataflow 中的 ActionBlock,但我无法弄清楚如何正确编写它。

类似这样。

        class Foo
        {
            ActionBlock<Task> runner;
            int index = 0;

            public async void TestTask(int index)
            {
                await Task.Delay(new Random().Next(1000, 10000));
                Debug.WriteLine("Task completed " + index);
            }

            public Foo()
            {
                runner = new ActionBlock<Task>(async task =>
                {
                    await task;
                });
            }

            private async void button_Click(object sender, RoutedEventArgs e)
            {
                // 应该发布 TestTask(intex) 以延迟执行 
                runner.Post(() => TestTask(index));
                index++;
            }
        }

也许有更好的方法来实现这个功能,或者一些聪明的架构来规避这些问题?

英文:

Application (wpf, .net framework 4.8) can receive some commands from outside (rpc, ui, etc) and can be received faster than can be executed. While commands work with hardware, I want them to be executed one by one.
I search for ideas, bc I do not even sure than my plan will work.

Me current idea is to somehow use ActionBlock from Dataflow, but I can't figure out how to properly write it.

Something like this.

        class Foo
        {
            ActionBlock&lt;Task&gt; runner;
            int index = 0;

            public async void TestTask(int index)
            {
                await Task.Delay(new Random().Next(1000, 10000));
                Debug.WriteLine(&quot;Task completed &quot; + index);
            }

            public Foo()
            {
                runner = new ActionBlock&lt;Task&gt;(task =&gt;
                {
                    task();
                });
            }

            private async void button_Click(object sender, RoutedEventArgs e)
            {
                // should post TestTask(intex) for delayed execution 
                runner.Post(???);
                index++;
            }
        }

May be there are better ways to achieve this functionality or some clever architecture to miss this problems?

答案1

得分: 2

以下是代码的翻译部分:

更简单的方法是只需传递一个异步委托类型,即 `Func&lt;Task&gt;`,然后使用闭包来创建委托实例:

```C#
ActionBlock&lt;Func&lt;Task&gt;&gt; runner;

public async Task TestTask(int index)
{
  await Task.Delay(new Random().Next(1000, 10000));
  Debug.WriteLine("任务完成 " + index);
}

public Foo()
{
  runner = new ActionBlock&lt;Func&lt;Task&gt;&gt;(async func =>
  {
    await func();
  });
}

private async void button_Click(object sender, RoutedEventArgs e)
{
  var indexValue = index++;
  runner.Post(() => TestTask(indexValue));
}

<details>
<summary>英文:</summary>

A simpler approach is to just pass in an asynchronous delegate type, i.e., `Func&lt;Task&gt;`, and use closures to create the delegate instances:

```C#
ActionBlock&lt;Func&lt;Task&gt;&gt; runner;

public async Task TestTask(int index)
{
  await Task.Delay(new Random().Next(1000, 10000));
  Debug.WriteLine(&quot;Task completed &quot; + index);
}

public Foo()
{
  runner = new ActionBlock&lt;Func&lt;Task&gt;&gt;(async func =&gt;
  {
    await func();
  });
}

private async void button_Click(object sender, RoutedEventArgs e)
{
  var indexValue = index++;
  runner.Post(() =&gt; TestTask(indexValue));
}

答案2

得分: -1

成功达到了我的期望。
大部分我的原始想法是正确的,只需要进行一些小修复。
以下是它们:

  • ActionBlock 应该接受委托和参数的元组
  • ActionBlock 的操作应该是异步的,并等待任务

展示我最终结果的最小代码:

class Foo
{
    delegate Task TaskDelegate(int book);
    ActionBlock<Tuple<TaskDelegate, int>> runner;
    int index = 0;

    public async Task TestTask(int index)
    {
        await Task.Delay(new Random().Next(1000, 10000));
        Debug.WriteLine("Task completed " + index);
    }

    public Foo()
    {
        runner = new ActionBlock<Tuple<TaskDelegate, int>>(async task =>
        {
            await task.Item1(task.Item2);
        });
    }

    private async void button_Click(object sender, RoutedEventArgs e)
    {
        runner.Post(Tuple.Create<TaskDelegate, int>(TestTask, index));
        index++;
    }
}
英文:

Managed to achieve what I expect.
Mostly my original idea was right, only minor fixes was needed.
Here they are:

  • ActionBlock should accept tuple of deletage and parameters
  • ActionBlock's actoin should be async and await for task

Minimal code to show my final result:

class Foo
{
    delegate Task TaskDelegate(int book);
    ActionBlock&lt;Tuple&lt;TaskDelegate, int&gt;&gt; runner;
    int index = 0;

    public async Task TestTask(int index)
    {
        await Task.Delay(new Random().Next(1000, 10000));
        Debug.WriteLine(&quot;Task completed &quot; + index);
    }

    public Foo()
    {
        runner = new ActionBlock&lt;Tuple&lt;TaskDelegate, int&gt;&gt;(async task =&gt;
        {
            await task.Item1(task.Item2);
        });
    }

    private async void button_Click(object sender, RoutedEventArgs e)
    {
        runner.Post(Tuple.Create&lt;TaskDelegate, int&gt;(TestTask, index));
        index++;
    }
}

huangapple
  • 本文由 发表于 2023年8月11日 00:34:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76877697.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定