简体   繁体   English

异步等待阻塞ui wp8

[英]async await blocking ui wp8

As far as I know the async await keywords work this way: when an await keyword is encountered by the compiler, it suspends the execution of the async function to the caller (in this case the dispatcher), waits for the awaitable function to complete in the background and then then returns back to the function. 据我所知async await关键字以这种方式工作:当编译器遇到await关键字时,它会暂停执行异步函数给调用者(在本例中是调度程序),等待等待函数完成后台然后返回到该函数。 Am I right? 我对吗?

here is what I am doing: 这就是我在做的事情:

async private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
     var p = await query("select* from notes", con);
}   

and here is the function being called 这是被调用的函数

 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;
 }

This blocks the UI thread. 这会阻止UI线程。 why is this happening shouldn't the control be transferred back to the dispatcher when it encounters the await keyword? 为什么发生这种情况不应该在遇到await关键字时将控制权转移回调度程序? If so why does the UI get stuck? 如果是这样,为什么用户界面会被卡住?

Your understanding of await is mostly correct, it's just incomplete. 您对await理解大多是正确的,它只是不完整。 await doesn't suspend execution of the current method immediately. await不会立即暂停执行当前方法。 First, the value to be awaited needs to be resolved to a value. 首先,需要将值等待解析为值。 Typically you'll have some sort of method that creates a Task . 通常,您将拥有一种创建Task的方法。 That task will be created synchronously , and then after creating that task, execution of the current method will end, and a continuation will be applied to that task that executes the remainder of the method. 该任务将同步创建 ,然后在创建该任务后,当前方法的执行将结束,并且将继续执行该任务以执行该方法的其余部分。

For an async method everything before the first await will be performed synchronously by the caller. 对于async方法,第一个await之前的所有内容都将由调用者同步执行。 It is when the first await (or the end of the method, or an exception that isn't caught by the method) that causes the method to return an actual Task . 当第一个await (或方法的结束,或方法未捕获的异常)导致该方法返回实际的Task

Your query method should be able to create the Task that represents the completion of the operation very quickly and then return, so that the caller can await that Task . 您的query方法应该能够非常快速地创建表示操作完成的Task ,然后返回,以便调用者可以awaitTask But it doesn't, it spends over 5 seconds creating the task that represents when it will finish, and when it ends up giving that task to its caller that Task has already finished. 但事实并非如此,它花费了超过5秒的时间来创建代表何时完成的任务,以及当它最终将任务交给其调用者Task已经完成时。

This means that Button_Tap can't yield to its caller (which is the UI's message loop) until after query has finished its 5 seconds of task creation. 这意味着在query完成任务创建5秒之后, Button_Tap无法屈服于调用者(这是UI的消息循环)。

All of this means that for Button_Tap to be asynchronous query needs to be asynchronous, and not asynchronous in that it uses the async keyword, but asynchronous in the sense that the method returns almost immediately when called, and that it performs its work after yielding control back to the caller. 所有这一切都意味着对于Button_Tap ,异步query需要是异步的,而不是异步的,因为它使用async关键字,但在调用时方法几乎立即返回,并且在产生控制后执行其工作的意义上是异步的回到来电者。

As to how to make the method asynchronous, that'll depend. 至于如何使方法异步,这将取决于。 For IO, such as querying a database, what you really want is to have the query provider itself provide inherently asynchronous support. 对于IO,例如查询数据库,您真正想要的是让查询提供程序本身提供固有的异步支持。 You want to have a query method that returns a Task that you can await , rather than synchronously returning its results. 您希望有一个返回可以awaitTask的查询方法,而不是同步返回其结果。 If you have no other choice, then as a last resort you can use Task.Run to perform the query in a non-UI thread and then await that. 如果您没有其他选择,那么作为最后的手段,您可以使用Task.Run在非UI线程中执行查询,然后await它。

As for the Thread.Sleep , that is also synchronously blocking the thread. 至于Thread.Sleep ,那也是同步阻塞线程。 You need to asynchronously do something after a set period of time instead (if you really do need the delay). 您需要在一段时间后异步执行某些操作(如果您确实需要延迟)。 You can use Task.Delay for that. 您可以使用Task.Delay

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

On a side note, you really shouldn't be trying to re-use your database connections like this. 另外,您真的不应该尝试重复使用这样的数据库连接。 They aren't designed to be used concurrently, for starters. 对于初学者来说,它们并非旨在同时使用。 Really they're inherently designed to perform just a single operation. 实际上它们本身就是为了执行一次操作而设计的。 You should be creating your connection right when you need it, and cleaning it up as soon as that one operation has been performed. 您应该在需要时立即创建连接,并在执行一个操作后立即清理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM