异步等待阻止 ui wp8 [英] async await blocking ui wp8

查看:15
本文介绍了异步等待阻止 ui wp8的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知 async await 关键字是这样工作的:当编译器遇到 await 关键字时,它会将异步函数的执行挂起到调用者(在这种情况下是调度程序),等待可等待函数在后台完成,然后返回函数.我说得对吗?

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. Am I right?

这是我在做什么:

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 会卡住?

This blocks the UI thread. why is this happening shouldn't the control be transferred back to the dispatcher when it encounters the await keyword? If so why does the UI get stuck?

推荐答案

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

Your understanding of await is mostly correct, it's just incomplete. await doesn't suspend execution of the current method immediately. 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. 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.

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

For an async method everything before the first await will be performed synchronously by the caller. 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.

你的query方法应该能很快创建代表操作完成的Task然后返回,这样调用者可以await那个Task.但事实并非如此,它花了超过 5 秒的时间来创建表示何时完成的任务,以及当它最终将该任务交给 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. 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.

这意味着 Button_Tapquery 完成其 5任务创建时间.

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.

所有这一切意味着 Button_Tap 是异步的 query 需要是异步的,而不是异步的,因为它使用了 async 关键字,但在某种意义上是异步的,因为该方法在被调用时几乎立即返回,并且在将控制权交还给调用者之后执行其工作.

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.

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

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. You want to have a query method that returns a Task that you can await, rather than synchronously returning its results. 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.

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

As for the Thread.Sleep, that is also synchronously blocking the thread. 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.

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.

这篇关于异步等待阻止 ui wp8的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆