依次运行动态添加的任务

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

Run dynamically added tasks one after one

问题

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

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

类似这样。

  1. class Foo
  2. {
  3. ActionBlock<Task> runner;
  4. int index = 0;
  5. public async void TestTask(int index)
  6. {
  7. await Task.Delay(new Random().Next(1000, 10000));
  8. Debug.WriteLine("Task completed " + index);
  9. }
  10. public Foo()
  11. {
  12. runner = new ActionBlock<Task>(async task =>
  13. {
  14. await task;
  15. });
  16. }
  17. private async void button_Click(object sender, RoutedEventArgs e)
  18. {
  19. // 应该发布 TestTask(intex) 以延迟执行
  20. runner.Post(() => TestTask(index));
  21. index++;
  22. }
  23. }

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

英文:

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.

  1. class Foo
  2. {
  3. ActionBlock&lt;Task&gt; runner;
  4. int index = 0;
  5. public async void TestTask(int index)
  6. {
  7. await Task.Delay(new Random().Next(1000, 10000));
  8. Debug.WriteLine(&quot;Task completed &quot; + index);
  9. }
  10. public Foo()
  11. {
  12. runner = new ActionBlock&lt;Task&gt;(task =&gt;
  13. {
  14. task();
  15. });
  16. }
  17. private async void button_Click(object sender, RoutedEventArgs e)
  18. {
  19. // should post TestTask(intex) for delayed execution
  20. runner.Post(???);
  21. index++;
  22. }
  23. }

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

答案1

得分: 2

以下是代码的翻译部分:

  1. 更简单的方法是只需传递一个异步委托类型,即 `Func&lt;Task&gt;`,然后使用闭包来创建委托实例:
  2. ```C#
  3. ActionBlock&lt;Func&lt;Task&gt;&gt; runner;
  4. public async Task TestTask(int index)
  5. {
  6. await Task.Delay(new Random().Next(1000, 10000));
  7. Debug.WriteLine("任务完成 " + index);
  8. }
  9. public Foo()
  10. {
  11. runner = new ActionBlock&lt;Func&lt;Task&gt;&gt;(async func =>
  12. {
  13. await func();
  14. });
  15. }
  16. private async void button_Click(object sender, RoutedEventArgs e)
  17. {
  18. var indexValue = index++;
  19. runner.Post(() => TestTask(indexValue));
  20. }
  1. <details>
  2. <summary>英文:</summary>
  3. 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:
  4. ```C#
  5. ActionBlock&lt;Func&lt;Task&gt;&gt; runner;
  6. public async Task TestTask(int index)
  7. {
  8. await Task.Delay(new Random().Next(1000, 10000));
  9. Debug.WriteLine(&quot;Task completed &quot; + index);
  10. }
  11. public Foo()
  12. {
  13. runner = new ActionBlock&lt;Func&lt;Task&gt;&gt;(async func =&gt;
  14. {
  15. await func();
  16. });
  17. }
  18. private async void button_Click(object sender, RoutedEventArgs e)
  19. {
  20. var indexValue = index++;
  21. runner.Post(() =&gt; TestTask(indexValue));
  22. }

答案2

得分: -1

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

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

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

  1. class Foo
  2. {
  3. delegate Task TaskDelegate(int book);
  4. ActionBlock<Tuple<TaskDelegate, int>> runner;
  5. int index = 0;
  6. public async Task TestTask(int index)
  7. {
  8. await Task.Delay(new Random().Next(1000, 10000));
  9. Debug.WriteLine("Task completed " + index);
  10. }
  11. public Foo()
  12. {
  13. runner = new ActionBlock<Tuple<TaskDelegate, int>>(async task =>
  14. {
  15. await task.Item1(task.Item2);
  16. });
  17. }
  18. private async void button_Click(object sender, RoutedEventArgs e)
  19. {
  20. runner.Post(Tuple.Create<TaskDelegate, int>(TestTask, index));
  21. index++;
  22. }
  23. }
英文:

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:

  1. class Foo
  2. {
  3. delegate Task TaskDelegate(int book);
  4. ActionBlock&lt;Tuple&lt;TaskDelegate, int&gt;&gt; runner;
  5. int index = 0;
  6. public async Task TestTask(int index)
  7. {
  8. await Task.Delay(new Random().Next(1000, 10000));
  9. Debug.WriteLine(&quot;Task completed &quot; + index);
  10. }
  11. public Foo()
  12. {
  13. runner = new ActionBlock&lt;Tuple&lt;TaskDelegate, int&gt;&gt;(async task =&gt;
  14. {
  15. await task.Item1(task.Item2);
  16. });
  17. }
  18. private async void button_Click(object sender, RoutedEventArgs e)
  19. {
  20. runner.Post(Tuple.Create&lt;TaskDelegate, int&gt;(TestTask, index));
  21. index++;
  22. }
  23. }

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:

确定