据我所知async await关键字以这种方式工作:当编译器遇到await关键字时,它会暂停执行异步函数给调用者(在本例中为调度程序),等待等待函数在后台完成然后返回到该函数。我是对的吗?
这是我正在做的事情:
async private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var p = await query("select* from notes", con);
}
这里是被称为
的函数 async Task<List<notes>> query(string sqlstring, SQLiteConnection con)
{
var p = con.Query<notes>(sqlstring);
Thread.Sleep(5000);
MessageBox.Show(p[0].Data);
return p;
}
这会阻止UI线程。为什么发生这种情况不应该在遇到await关键字时将控制权转移回调度程序?如果是这样,为什么UI会被卡住?
答案 0 :(得分:13)
您对await
的理解主要是正确,它只是不完整。 await
不会立即暂停执行当前方法。首先,需要将值等待解析为值。通常,您会使用某种方法创建Task
。 该任务将同步创建,然后在创建该任务后,当前方法的执行将结束,并且将继续执行该任务以执行该方法的其余部分。
对于async
方法,调用者将同步执行第一个await
之前的所有内容。当第一个await
(或方法的结尾,或方法未捕获的异常)导致该方法返回实际的Task
时。
您的query
方法应能够非常快速地创建表示操作完成的Task
,然后返回,以便调用方可以{{1}那await
。但事实并非如此,它会花费超过5秒的时间来创建代表何时完成的任务,以及何时最终将该任务交给其Task
已完成的调用者。
这意味着Task
无法屈服于其调用者(这是UI的消息循环),直到Button_Tap
完成其5秒的任务创建。< / p>
所有这一切都意味着query
要异步Button_Tap
需要异步,而不是异步,因为它使用query
关键字,但在方法意义上是异步的在被调用时几乎立即返回,并且在将控制权交还给调用者之后执行其工作。
至于如何使方法异步,这将取决于。对于IO,例如查询数据库,您真正想要的是让查询提供程序本身提供固有的异步支持。您希望拥有一个可以async
返回Task
的查询方法,而不是同步返回其结果。如果您没有其他选择,那么作为最后的手段,您可以使用await
在非UI线程中执行查询,然后使用Task.Run
。{/ p>
对于await
,它也同步阻塞线程。您需要在一段时间后异步执行某些操作(如果您确实需要延迟)。您可以使用Thread.Sleep
。
Task.Delay
另一方面,您真的不应该尝试重新使用这样的数据库连接。对于初学者来说,它们并非旨在同时使用。实际上它们本身就是为了执行一次操作而设计的。您应该在需要时立即创建连接,并在执行一个操作后立即清理它。