【问题标题】:C# 6 waiting for full completion of task and all subtasksC# 6 等待任务和所有子任务完全完成
【发布时间】:2017-10-10 07:55:23
【问题描述】:

我正在尝试构建一种调度程序(这可能不是相关术语),它可以按顺序运行多个任务。

这是我的 POC 代码(请忽略队列/出队机制很差,但我猜这里不是问题)

编辑:感谢@Theraot的帮助

    static void Main(string[] args)
    {
        ProcessingQueue o_q = new ProcessingQueue();
        o_q.Enqueue(async () => { await SimulateTaskSequence(1); });
        o_q.Enqueue(async () => { await SimulateTaskSequence(2); });

        Console.ReadLine();
    }

    public static async Task SimulateTaskSequence(int taskNbr)
    {
        Console.WriteLine("T{0} - Working 1sec", taskNbr);
        Thread.Sleep(1000);

        Console.WriteLine("T{0} - Zzz 1st 1sec", taskNbr);
        await Task.Delay(1000);

        Console.WriteLine("T{0} - Working 1sec", taskNbr);
        Thread.Sleep(1000);

        Console.WriteLine("T{0} - Done", taskNbr);
    }

    public class ProcessingQueue
    {
        Queue<Action> _Queue = new Queue<Action>();
        private bool _stillRunning = false;

        public void Enqueue(Action a)
        {
            lock (_Queue)
            {
                _Queue.Enqueue(a);

                if (_stillRunning == false)
                {
                    StartProcessing();
                }
            }
        }


        private void StartProcessing()
        {
            _stillRunning = true;

            Task.Run(async () =>
            {
                Action a = null;

                while (true)
                {
                    lock (_Queue)
                    {
                        if (_Queue.Any() == true)
                        {
                            a = _Queue.Dequeue();
                        }
                        else
                        {
                            break;
                        }
                    }

                    await Task.Run(a); //how to wait for all subtasks!!???
                }
                _stillRunning = false;
            });
        }

我的问题是,一旦第一个任务 (T1) 的第一个等待发生,第二个任务 (T2) 就会开始执行。

我得到以下输出:

T1 - Working 1sec
T1 - Zzz 1st 1sec
T2 - Working 1sec
T2 - Zzz 1st 1sec
T1 - Working 1sec
T1 - Done
T2 - Working 1sec
T2 - Done

但我期待的是:

T1 - Working 1sec
T1 - Zzz 1st 1sec
T1 - Working 1sec
T1 - Done
T2 - Working 1sec
T2 - Zzz 1st 1sec
T2 - Working 1sec
T2 - Done

我理解为什么这是默认行为,但我需要更改它。我在一个新的 TaskFactory 中玩 TaskContinuationOptions 和 TaskCreationOptions,但没有更好的结果。 这可能吗?

非常感谢 克里斯托夫

【问题讨论】:

  • 你的ProcessingQueue类已经存在于框架中,它是ThreadPool。很难正确替换,它不会做任何 ThreadPool 不会做的事情。除了等待之外,很快就出错了。不要这样做。
  • @HansPassant OP 想要的与 ThreadPool 不同,因为 OP 希望添加的任务按顺序完成。在 ThreadPool 上你没有这样的保证,实际上 ThreadPool 的想法是使用多个线程并行运行事物(编辑:并重用线程,当然)。现在,这可以通过同步运行这些任务来完成,或者通过使用线程等待的其他方式来完成...... OP 也不想要任何这些。
  • Task 类的组合非常好,他只需要 ContinueWith 来对主任务进行排序,WaitAll 来等待子任务完成。很简单,但是当你发明自己的线程池时就很难看到了。

标签: .net multithreading asynchronous task taskscheduler


【解决方案1】:

我建议创建一个ProcessingQueue&lt;Func&lt;Task&gt;&gt; 而不是ProcessingQueue&lt;Action&gt;

public class ProcessingQueue
{
    Queue<Func<Task>> _Queue = new Queue<Func<Task>>();

    private bool _stillRunning = false;

    public void Enqueue(Func<Task> a)
    {
        lock (_Queue)
        {
            _Queue.Enqueue(a);

            if (_stillRunning == false)
            {
                StartProcessing();
            }
        }
    }

    private void StartProcessing()
    {
        _stillRunning = true;

        Task.Run(async () =>
        {
            Func<Task> a = null;

            while (true)
            {
                lock (_Queue)
                {
                    if (_Queue.Any() == true)
                    {
                        a = _Queue.Dequeue();
                    }
                    else
                    {
                        break;
                    }
                }

                await a(); //how to wait for all subtasks!!???
            }
            _stillRunning = false;
        });
    }

说明

在有问题的代码中,

Action a;
...
await Task.Run(a);

您正在执行Task.Run(Action action),因为操作可能包含异步任务,Run 方法不会等待任务,因为没有任务。当你调用 Task.Run(Func&lt;Task&gt; task) Run 方法知道它是任务并且它会等待它,

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多