class Program
{
static void Main(string[] args)
{
var a = new A();
var result = a.Method();
Console.Read();
}
}
class A
{
public async Task<string> Method()
{
await Task.Run(new Action(MethodA));
await Task.Run(new Action(MethodB));
return "done";
}
public async void MethodA()
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine("MethodA" + i);
await Task.Delay(1000);
}
}
public async void MethodB()
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine("MethodB" + i);
await Task.Delay(1000);
}
}
}
我想这里的期望是先输出MethodA1,MethodA2...MethodA9然后开始输出MethodB1...MethodB9。
但似乎不是。有人对此有解释吗?谢谢!
编辑:
感谢您的回复。实际上我知道如何输出正确的结果,但只是想知道为什么我的代码表现得很奇怪,因为我认为这违背了我对 async/await 的了解。
class A
{
public async Task<string> Method()
{
await Task.Run(new Action(MethodA));
await Task.Run(async () => {
for (var i=0;i<10;i++)
await Task.Delay(100);
Console.WriteLine("should output before done");
});
return "done";
}
public async void MethodA()
{
var returnString = string.Empty;
for (var i = 0; i < 10; i++)
{
await Task.Delay(200);
}
Console.WriteLine("MethodA " + Thread.CurrentThread.ManagedThreadId);
}
}
我简化了代码,现在是这样的。第一个 await 快速将控制转移到下一个 await,然后第二个 await 的行为符合我的预期,最后输出“完成”。但我不知道是什么造成了这里的差异。
更新:请记住示例代码是一种不好的做法。你可以read this post for more information
和 friend 建议的区别在于
await Task.Run(new Action(MethodA));
不等于
await Task.Run(async () => {
for (var i=0;i<10;i++)
await Task.Delay(100);
Console.WriteLine("should output before done");
});
前者以同步方式调用“methodA”,而海报者是正确的异步调用。但这仍然让我感到困惑,因为如果这是真的,那么异步操作可以而且只能由 lambda 表达式表示。我的意思是,没有像“new async Action(...)”这样的东西吧?
更新:
我尝试了 Task.Factory.StartNew(Action action) ,它被认为等同于 Task.Run(Action action) 并且事情再次发生了变化:
class A
{
public async Task<string> Method()
{
await Task.Factory.StartNew(new Action(MethodA));
await Task.Factory.StartNew(async () => {
for (var i=0;i<10;i++)
await Task.Delay(100);
Console.WriteLine("should output before done");
});
return "done";
}
public async void MethodA()
{
for (var i = 0; i < 10; i++)
await Task.Delay(200);
Console.WriteLine("MethodA");
}
}
我想我需要更多帮助...
最佳答案
你的代码表现如此的原因是因为你开始调用其中一个方法的任务将在方法中的第一个 await
完成,因为它是 async void
并继续,从而导致 await Task.Run(new Action(MethodA));
在您的 MethodA
主体仍在运行时将控制权返回给线程。这是因为 async void
基本上是即发即忘。
以下是您的代码的简化版本中发生的情况。
class A
{
public async Task<string> Method()
{
// You create a task to run MethodA
await Task.Run(new Action(MethodA));
// control returns here on the first `await` in MethodA because
// it is `async void`.
return "done";
}
public async void MethodA()
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine("MethodA" + i);
// Here the control is returned to the thread and because
// it's `async void` an `await` will only block until you reach
// this point the first time.
await Task.Delay(1000); //
}
}
}
要获得您想要的结果,您首先需要从您的方法中返回一个 Task
,以便可以等待它们。那么您也不需要 Task.Run
。
class A
{
public async Task<string> Method()
{
await MethodA();
await MethodB();
return "done";
}
public async Task MethodA()
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine("MethodA" + i);
await Task.Delay(1000);
}
}
public async Task MethodB()
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine("MethodB" + i);
await Task.Delay(1000);
}
}
}
关于c# - 使用异步等待时出现意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35803629/