C#中的异步方法不是异步的吗?
创建了以下控制台应用程序后,我有点困惑为什么它似乎同步运行而不是异步运行:
class Program { static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); var total = CreateMultipleTasks(); stopwatch.Stop(); Console.WriteLine("Total jobs done: {0} ms", total.Result); Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds); } static async Task CreateMultipleTasks() { var task1 = WaitForMeAsync(5000); var task2 = WaitForMeAsync(3000); var task3 = WaitForMeAsync(4000); var val1 = await task1; var val2 = await task2; var val3 = await task3; return val1 + val2 + val3; } static Task WaitForMeAsync(int ms) { Thread.Sleep(ms); return Task.FromResult(ms); } }
运行应用程序时,输出为:
完成的工作总数:12000毫秒
工作完成时间:12003毫秒
我本来期待像:
完成的工作总数:12000毫秒
工作完成时间:5003毫秒
这是因为当我使用Thread.Sleep方法时它会停止进一步执行整个应用程序吗? 或者我错过了一些重要的东西?
您以同步方式运行任务。 你可以这样做:
static async Task CreateMultipleTasks() { var task1 = Task.Run (() => WaitForMeAsync(5000)); var task2 = Task.Run (() => WaitForMeAsync(3000)); var task3 = Task.Run (() => WaitForMeAsync(4000)); Task.WaitAll(new Task[] { task1, task2, task3 }); return task1.Result + task2.Result + taks3.Result; }
连续使用三个await
不会并行运行任务。 它将在等待时释放线程(如果您使用await Task.Delay(ms)
因为Thread.Sleep(ms)
是阻塞操作),但当await Task.Delay(ms)
“hibernate”状态时,当前执行将不会继续执行task2
。
即使你转换为使用Task.Run
或Task.Delay
如其他答案所示, 你应该尽可能避免在async
方法中的任何地方使用阻塞Task.WaitAll
。 混合异步和同步代码通常是一个坏主意,它会增加冗余阻塞线程的数量并促进死锁。
相反,使用await Task.WhenAll
并将阻塞等待移动到顶层(即,在这种情况下为Main
方法):
class Program { static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); var total = CreateMultipleTasks(); total.Wait(); stopwatch.Stop(); Console.WriteLine("Total jobs done: {0} ms", total.Result); Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds); } static async Task CreateMultipleTasks() { var task1 = Task.Run(() => WaitForMeAsync(5000)); var task2 = Task.Run(() => WaitForMeAsync(3000)); var task3 = Task.Run(() => WaitForMeAsync(4000)); await Task.WhenAll(new Task[] { task1, task2, task3 }); return task1.Result + task2.Result + task3.Result; } static int WaitForMeAsync(int ms) { // assume Thread.Sleep is a placeholder for a CPU-bound work item Thread.Sleep(ms); return ms; } }
另外,请查看Stephen Toub的“我应该为同步方法公开异步包装器吗?” 和“我应该为同步方法公开异步包装器吗?”
您的WaitForMeAsync方法只是一个假装为异步的简单同步方法。
你不执行任何异步操作,Sleep()只是阻塞线程。
为什么要延迟异步? (是的,你可以使用await Task.Delay(ms)
),需要更多的输入来帮助那里。