如何在从C#中的方法返回之前等待所有任务完成

时间:2016-06-27 08:07:35

标签: c# async-await task-parallel-library

在我的Web API控制器 MyController 中,调用了我的服务类

   [HttpPost]
   Route("groupmembershipvalidate")]
   public IHttpActionResult PostGroupMembershipValidate(ListGroupMembershipUploadInput ListGroupMembershipUploadInput) 
   {

    //perform some tasks

    var searchResults =  ts.validateDetails(gmvi);

    return Ok(searchResults);

   }

现在这个 validateDetails 服务类需要并行运行某些任务,需要等待所有结果返回,然后才返回。

        var tasks = new Task[]
        {
            Task.Factory.StartNew(() => gd.validateChapterCodeDetails(_input1)),
            Task.Factory.StartNew(() => gd.validateGroupCodeDetails(_input1)),
            Task.Factory.StartNew(() => gd.validateMasterIdDetails(_input1))
        };

       var things = Task.WhenAll(tasks);

       //Some tasks

       return result;

在所有任务返回结果之前,不会计算返回的结果。但是当Task.WhenAll(任务)被命中时,它会立即移动到接下来的几行并返回 PostGroupMembershipValidate 控制器方法。

如何在返回值之前等待并在获取所有值后才返回?

4 个答案:

答案 0 :(得分:1)

如果可以使用all创建一个新任务,该任务在其中的所有任务完成时完成,则可以使用常规异步模式继续从该任务中提取结果。

https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.whenall(v=vs.110).aspx

所以     //如果您的验证结果是字符串:     任务[]任务= ...     var things = await Task.WhenAll(tasks);

或者可以使用WaitAll,但是如果你需要在输出上做这个笨拙的方法。无论如何,留在异步环境中的IMO总是更好。

Task.WaitAll(tasks);
foreach(var t in tasks) DoSomething(t.Result);

https://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx

此外,它会阻止当前的线程AFAIK。

更完整的控制台示例: https://dotnetfiddle.net/JMLHxR

using System;
using System.Threading.Tasks;

public class Program
{
    private static int counter = 0;

    public static void Main()
    {
        Random rnd = new Random();
        var tasks = new Task<object>[]
        {
            // If your target method returns a task.
            //  - note: A Proxy or similar approach will probably be more readable.
            CreateTask(rnd.Next(500,2000)).ContinueWith(t => (object)t.Result),
            CreateOtherTask(rnd.Next(500,2000)).ContinueWith(t => (object)t.Result),
            CreateTask(rnd.Next(500,2000)).ContinueWith(t => (object)t.Result),
            CreateOtherTask(rnd.Next(500,2000)).ContinueWith(t => (object)t.Result),

            //If your target method is syncronious.
            Task.Run(() => (object)CreateSimple()),
            Task.Run(() => (object)CreateMessage()),
            Task.Run(() => (object)CreateSimple()),
            Task.Run(() => (object)CreateMessage())
        };      

        Task.WaitAll(tasks);
        foreach(var t in tasks)
            Console.WriteLine(t.Result);

        // They are already completed here, but just to show the syntax.
        // .Result should obvisously be awaited instead.
        var all = Task.WhenAll(tasks).Result;
        foreach(var result in all)
            Console.WriteLine(result);
    }


    private static string CreateSimple()
    {
        int id = Program.counter++;
        return "Task [" + id + "] delayed: NONE";
    }

    private static Message CreateMessage()
    {
        return new Message(CreateSimple());
    }

    private static async Task<string> CreateTask(int delay)
    {
        int id = Program.counter++;
        await Task.Delay(delay);
        return "Task [" + id + "] delayed: " + delay;
    }

    private static async Task<Message> CreateOtherTask(int delay)
    {
        int id = Program.counter++;
        await Task.Delay(delay);
        return new Message("Task [" + id + "] delayed: " + delay);
    }

    public class Message {
        private string message;

        public Message(string msg) { message = msg; }

        public override string ToString(){ return message; }
    }
}

答案 1 :(得分:1)

您正在寻找类似的东西

public class Sample1
{

    public void Run()
    {
        foreach ( var item in Validate( "foobar" ).Result )
        {
            Console.WriteLine( item );
        }
    }

    // starts some result producing tasks
    // await all of them 
    // return the result of each task
    public async Task<IEnumerable> Validate( string input )
    {
        var tasks = new Task<object>[ ] {
            Task.Run( ()=> (object) ValidateFoo(input) ),
            Task.Run( ()=> (object) ValidateBar(input) ),
        };

        return await Task.WhenAll( tasks );
    }

    private string ValidateFoo( string input )
    {
        return "foo";
    }

    private bool ValidateBar( string input )
    {
        return true;
    }

}

答案 2 :(得分:0)

    static void Main(string[] args)
    {
        Console.WriteLine("Started");
        Task.WaitAll(task1(), task2());
        Console.WriteLine("Ended");
    }

    static async Task<string> task1()
    {
        Console.WriteLine("Started task1");
        var task = await Task.Run(() => { return "task1"; });
        Console.WriteLine("Ended task1");
        return task;
    }

    static async Task<string> task2()
    {
        Console.WriteLine("Started task2");
        var task = await Task.Run(() => { return "task2"; });
        Console.WriteLine("Ended task2");
        return task;
    }
}

生成此输出:

Started
Started task1
Ended task1
Started task2
Ended task2
Ended
Press any key to continue . . .

答案 3 :(得分:0)

var task1 = T1();
var task2 = T2();

await Task.WhenAll(task1, task2);