Sequential processing of asynchronous tasks

前端 未结 5 583
旧时难觅i
旧时难觅i 2020-12-08 02:53

Assume the following synchronous code:

try
{
    Foo();
    Bar();
    Fubar();
    Console.WriteLine(\"All done\");
}
catch(Exception e) // For illustration         


        
5条回答
  •  甜味超标
    2020-12-08 02:58

    Now, I haven't really used the TPL much, so this is just a stab in the dark. And given what @Servy mentioned, perhaps this won't run completely asynchronously. But I figured I'd post it and if it's way off the mark, you can downvote me to oblivion or I can have it deleted (or we can just fix what needs fixing)

    public void RunAsync(Action onComplete, Action errorHandler, params Action[] actions)
    {
        if (actions.Length == 0)
        {
            //what to do when no actions/tasks provided?
            onComplete();
            return;
        }
    
        List tasks = new List(actions.Length);
        foreach(var action in actions)
        {
            Task task = new Task(action);
            task.ContinueWith(t => errorHandler(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
            tasks.Add(task);
        }
    
        //last task calls onComplete
        tasks[actions.Length - 1].ContinueWith(t => onComplete(), TaskContinuationOptions.OnlyOnRanToCompletion);
    
        //wire all tasks to execute the next one, except of course, the last task
        for (int i = 0; i <= actions.Length - 2; i++)
        {
            var nextTask = tasks[i + 1];
            tasks[i].ContinueWith(t => nextTask.Start(), TaskContinuationOptions.OnlyOnRanToCompletion);
        }
    
        tasks[0].Start();
    }
    

    And it would have usage like:

    RunAsync(() => Console.WriteLine("All done"),
                ex => Console.WriteLine(ex),
                Foo,
                Bar,
                Fubar);
    

    Thoughts? Downvotes? :)

    (I definitely prefer async/await though)

    EDIT: Based on your comments to take Func, would this be a proper implementation?

    public void RunAsync(Action onComplete, Action errorHandler, params Func[] actions)
    {
        if (actions.Length == 0)
        {
            //what to do when no actions/tasks provided?
            onComplete();
            return;
        }
    
        List tasks = new List(actions.Length);
        foreach (var action in actions)
        {
            Func nextActionFunc = action;
            Task task = new Task(() =>
            {
                var nextTask = nextActionFunc();
                nextTask.ContinueWith(t => errorHandler(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
                nextTask.Start();
            });
            tasks.Add(task);
        }
    
        //last task calls onComplete
        tasks[actions.Length - 1].ContinueWith(t => onComplete(), TaskContinuationOptions.OnlyOnRanToCompletion);
    
        //wire all tasks to execute the next one, except of course, the last task
        for (int i = 0; i <= actions.Length - 2; i++)
        {
            var nextTask = tasks[i + 1];
            tasks[i].ContinueWith(t => nextTask.Start(), TaskContinuationOptions.OnlyOnRanToCompletion);
        }
    
        tasks[0].Start();
    }
    

提交回复
热议问题