C# 对异步/等待函数的误解
我使用C#/VS2012/.Net4.0/Microsoft.Bcl.async NuGet包 在前面的问题之后,我尝试使用async/await来避免冻结UI。但我的每一次测试都没有成功 主要功能是做一项繁重的工作,如下所示:C# 对异步/等待函数的误解,c#,.net,asynchronous,async-await,C#,.net,Asynchronous,Async Await,我使用C#/VS2012/.Net4.0/Microsoft.Bcl.async NuGet包 在前面的问题之后,我尝试使用async/await来避免冻结UI。但我的每一次测试都没有成功 主要功能是做一项繁重的工作,如下所示: public bool PopulateTV() { using (WaitingForm waitingForm=new WaitingForm()) { waitingForm.Show(); bool boolResult=DoHeavyW
public bool PopulateTV()
{
using (WaitingForm waitingForm=new WaitingForm())
{
waitingForm.Show();
bool boolResult=DoHeavyWork(); //UI is freezing, waitingForm() doesn't show correctly
return boolResult;
}
}
对该函数的调用类似于
if(!PopulateTV())
{
}
我尝试实现异步/等待
public async Task<bool> populateTV()
{
using (WaitingForm waitingForm=new WaitingForm())
{
Task<bool> func=DoHeavyWork();
bool boolResult=await func;
return boolResult;
}
}
public Task<bool> DoHeavyWork()
{
//do the work
return boolResult;
}
这一次,没有错误,只是一个警告(我使用的是非英语版本的VS,所以我翻译了错误/警告消息):
此异步方法没有等待运算符,因此它将执行
作为同步的
这只是一个警告,但为什么我会收到这个信息
但这不是大问题。调用父方法PopulateTV()时,我希望返回一个bool值(如果(!PopulateTV())…
我得到一个错误:
!无法使用运算符
使用“System.Threading.Tasks.Task”
当然。但是PopulateTV()
返回bool
(returnboolresult;
),即使方法声明使用Task
我的错误在哪里?您实际上并不是在一个单独的线程中运行繁重的代码-异步并不自动保证这一点 尝试类似于
(等待任务。运行(()=>DoHeavyWork());
但这不是大问题。当我调用父方法时
PopulateTV(),我想返回一个bool值(如果(!PopulateTV())…和
我得到一个错误:
如果(!(wait PopulateTV()),则为。首先等待结果(bool),然后对其进行评估
另一方面,您的异步方法并不等同于这样编码:
public Task<bool> DoHeavyWork()
{
//do the work
return Task.FromResult(true);
}
public Task<bool> DoHeavyWork()
{
return Task.Factory.StartNew
(
() =>
{
Thread.Sleep(10000);
return true;
}
)
}
public async bool PopulateTV()
{
using (var waitingForm = new WaitingForm())
{
waitingForm.Show();
return await Task.Run(() => DoHeavyWork());
}
}
…与这样写几乎是一样的:
public Task<bool> DoHeavyWork()
{
//do the work
return Task.FromResult(true);
}
public Task<bool> DoHeavyWork()
{
return Task.Factory.StartNew
(
() =>
{
Thread.Sleep(10000);
return true;
}
)
}
public async bool PopulateTV()
{
using (var waitingForm = new WaitingForm())
{
waitingForm.Show();
return await Task.Run(() => DoHeavyWork());
}
}
…这也可以使用Task.FromResult(T result)
简化,因为您可以检入此答案的一些代码片段
那么,为什么我需要使用基于任务的异步模式(TAP)开发我的API呢?
因为方法的调用方不需要知道方法是同步的还是异步的。方法的实现将决定它,但同时,如果整个方法实际上是异步的,调用方可以异步工作
如果您执行相反的操作(同步方法),那么如果您决定将所有操作都实现为异步操作,则需要更改整个代码流:
// I don't know if it's actually async or not, I don't care. The calling method
// decides it.
bool result = await DoWorkAsync();
// I know it's sync. So my code can become pure garbage if I need to make it
// synchronous since it can't be awaited and it doesn't return a Task instance!
bool result = DoWork();
是正确的,但只需直接返回任务
即可避免开销和脆弱性:
public Task<bool> DoHeavyWork()
{
return Task.Run(() =>
{
return HeavyWorkReturningBool();
});
}
DoHeavyWork
仍然是一种常规的同步方法:
public bool DoHeavyWork()
{
var boolResult;
//do the work
return boolResult;
}
有关详细信息,请参阅以下博客帖子:
但是PopulateTV()
返回bool(return boolResult;),即使
方法声明使用任务
错误。PopulateTV()
返回一个任务
为什么在这样声明方法时会收到警告
public async Task<bool> DoHeavyWork()
将整个方法体包装在任务中的代码。Run
对其行为撒谎;它为一个伪异步方法公开了一个异步API。从长远来看,将对任务中方法的调用包装在任务中。Run
更易于维护。@StephenCleary,我不明白“伪异步”是什么意思。lambda中的所有内容不是都传递给Task.Run()
以异步方式运行吗?不过我同意您关于可维护性的观点。其目的是包装单个调用,但我使用了中间result
变量,以更明确地说明如何使用Task
(即,在lambda内部,one只返回一个由任务
的类型参数指示的类型值。我稍微更改了代码示例。“异步”可能意味着一些不同的事情。我将工作推送到后台线程称为“伪异步”,因为所有的代码都是通过使用另一个线程释放当前线程。相反,“真正的异步”代码不使用任何线程(一个示例是异步I/O)。在op的情况下,有只有同步的工作要做,所以使方法签名异步在我看来是误导性的。我在我的博客上有一个较长的描述,附加的改变是使DoHeavyWork
returnbool
而不是Task
。我认为这有点暗示:我喜欢你的网站。
if (!(await PopulateTV()))
public async Task<bool> DoHeavyWork()
public Task<bool> DoHeavyWork()
{
return Task.Run<bool>(() =>
//do the heavy work
return boolResult;
);
}