并行运行两个异步任务并在.NET 4.5中收集结果

我已经尝试了一段时间来得到一些我认为可以简单使用.NET 4.5的东西

我希望同时执行两个长时间运行的任务,并收集
以最佳的 C # 4.5(RTM)方式生成

下面的方法可行,但我不喜欢,因为:

  • 我希望 Sleep是一个异步方法,这样它就可以 await其他方法
  • 它只是看起来笨拙的 Task.Run()
  • 我不认为这是甚至使用任何新的语言功能在所有!

工作守则:

public static void Go()
{
Console.WriteLine("Starting");


var task1 = Task.Run(() => Sleep(5000));
var task2 = Task.Run(() => Sleep(3000));


int totalSlept = task1.Result + task2.Result;


Console.WriteLine("Slept for a total of " + totalSlept + " ms");
}


private static int Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
Console.WriteLine("Sleeping for " + ms + " FINISHED");
return ms;
}

非工作守则:

更新: 这实际上是正确的工作方式,唯一的问题是 Thread.Sleep

这段代码不起作用,因为对 Sleep(5000)的调用会立即启动正在运行的任务,所以 Sleep(1000)在完成之前不会运行。这是真实的,即使 Sleepasync,我没有使用 await或调用 .Result太早。

我想也许有一种方法可以通过调用一个 async方法来得到一个不运行的 Task<T>,这样我就可以在这两个任务上调用 Start(),但是我不知道如何通过调用一个异步方法来得到一个 Task<T>

public static void Go()
{
Console.WriteLine("Starting");


var task1 = Sleep(5000);    // blocks
var task2 = Sleep(1000);


int totalSlept = task1.Result + task2.Result;


Console.WriteLine("Slept for " + totalSlept + " ms");
}


private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
return ms;
}
181510 次浏览

虽然 Sleep方法是异步的,但 Thread.Sleep不是。异步的整体思想是重用单个线程,而不是启动多个线程。因为您使用对 Thread 的同步调用阻塞了。睡吧,没用的。

我假设 Thread.Sleep是您实际想要做的事情的简化。您的实际实现能够被编码为异步方法吗?

如果您确实需要运行多个同步阻塞调用,那么我认为应该寻找其他方法!

您应该使用 Task。对于异步编程,使用“延迟”代替“睡眠”,然后使用“任务”。When All 组合任务结果。这些任务将并行运行。

public class Program
{
static void Main(string[] args)
{
Go();
}
public static void Go()
{
GoAsync();
Console.ReadLine();
}
public static async void GoAsync()
{


Console.WriteLine("Starting");


var task1 = Sleep(5000);
var task2 = Sleep(3000);


int[] result = await Task.WhenAll(task1, task2);


Console.WriteLine("Slept for a total of " + result.Sum() + " ms");


}


private async static Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount);
await Task.Delay(ms);
Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount);
return ms;
}
}

这篇文章帮助解释了很多事情。

异步/等待常见问题解答

这一部分解释了为什么 Thread.Sleep在同一个原始线程上运行——这导致了我最初的困惑。

关键字是否会导致对队列的方法的调用 线程池? 创建一个新的线程? 发射火箭飞船到 火星

不,不,不,看前面的问题“异步”关键词 指示编译器可以在 方法,这样该方法可以在等待点暂停,并具有 当等待的实例 这就是为什么编译器会发出警告,如果没有 在标记为“异步”的方法内部“等待”。

async Task<int> LongTask1() {
...
return 0;
}


async Task<int> LongTask2() {
...
return 1;
}


...
{
Task<int> t1 = LongTask1();
Task<int> t2 = LongTask2();
await Task.WhenAll(t1,t2);
//now we have t1.Result and t2.Result
}

为了回答这个问题:

我希望睡眠是一个异步方法,这样它就可以等待其他方法

你也许可以像这样重写 Sleep函数:

private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
var task = Task.Run(() => Thread.Sleep(ms));
await task;
Console.WriteLine("Sleeping for " + ms + "END");
return ms;
}


static void Main(string[] args)
{
Console.WriteLine("Starting");


var task1 = Sleep(2000);
var task2 = Sleep(1000);


int totalSlept = task1.Result +task2.Result;


Console.WriteLine("Slept for " + totalSlept + " ms");
Console.ReadKey();
}

运行此代码将输出:

Starting
Sleeping for 2000
Sleeping for 1000
*(one second later)*
Sleeping for 1000END
*(one second later)*
Sleeping for 2000END
Slept for 3000 ms

现在是 周末了!

    public async void Go()
{
Console.WriteLine("Start fosterage...");


var t1 = Sleep(5000, "Kevin");
var t2 = Sleep(3000, "Jerry");
var result = await Task.WhenAll(t1, t2);


Console.WriteLine($"My precious spare time last for only {result.Max()}ms");
Console.WriteLine("Press any key and take same beer...");
Console.ReadKey();
}


private static async Task<int> Sleep(int ms, string name)
{
Console.WriteLine($"{name} going to sleep for {ms}ms :)");
await Task.Delay(ms);
Console.WriteLine("${name} waked up after {ms}ms :(";
return ms;
}