异步等待阻止ui wp8

据我所知,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> query(string sqlstring, SQLiteConnection con) { var p = con.Query(sqlstring); Thread.Sleep(5000); MessageBox.Show(p[0].Data); return p; } 

这会阻止UI线程。 为什么发生这种情况不应该在遇到await关键字时将控制权转移回调度程序? 如果是这样,为什么用户界面会被卡住?

您对await理解大多是正确的,它只是不完整。 await不会立即暂停执行当前方法。 首先,需要将等待的值解析为值。 通常,您将拥有一种创建Task的方法。 该任务将同步创建 ,然后在创建该任务后,当前方法的执行将结束,并且将继续执行该任务以执行该方法的其余部分。

对于async方法,第一个await之前的所有内容都将由调用者同步执行。 当第一个await (或方法的结束,或方法未捕获的exception)导致该方法返回实际的Task

您的query方法应该能够非常快速地创建表示操作完成的Task ,然后返回,以便调用者可以awaitTask 。 但事实并非如此,它花费了超过5秒的时间来创建表示它何时完成的任务,以及当它最终将任务交给其调用者Task已经完成时。

这意味着在query完成任务创建5秒之后, Button_Tap无法屈服于调用者(这是UI的消息循环)。

所有这一切都意味着对于Button_Tap ,异步query需要是异步的,而不是异步的,因为它使用async关键字,但是在调用时方法几乎立即返回的意义上是异步的,并且它在产生控制之后执行其工作回到来电者。

至于如何使方法异步,这将取决于。 对于IO,例如查询数据库,您真正想要的是让查询提供程序本身提供固有的异步支持。 您希望有一个查询方法返回您可以awaitTask ,而不是同步返回其结果。 如果您没有其他选择,那么作为最后的手段,您可以使用Task.Run在非UI线程中执行查询,然后await它。

至于Thread.Sleep ,那也是同步阻塞线程。 您需要在一段时间后异步执行某些操作(如果您确实需要延迟)。 您可以使用Task.Delay

 async Task> query(string sqlstring, SQLiteConnection con) { var p = await con.QueryAsync(sqlstring); //Or, if there is no asynchronous query method //var p = await Task.Run(() => con.Query(sqlstring)); await Task.Delay(5000); MessageBox.Show(p[0].Data); return p; } 

另外,您真的不应该尝试重新使用这样的数据库连接。 对于初学者来说,它们并非旨在同时使用。 实际上它们本身就是为了执行一次操作而设计的。 您应该在需要时立即创建连接,并在执行一个操作后立即清理它。