Application.DoEvents与循环等待a Task.Delay [英] Application.DoEvents vs await Task.Delay in a loop

查看:201
本文介绍了Application.DoEvents与循环等待a Task.Delay的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最令我感到不满的是,我需要在其中一个应用程序中使用WebBrowser控件.

Much to my discontent, I need to use a WebBrowser control in one of my apps.

我还需要做的一件事是等待元素变得可见/类更改等,这在触发DocumentCompleted事件之后发生得很好,对于我来说,使该事件几乎变得毫无用处.

One of the things I also need to do is wait for an element to become visible/class changes/etc, which happens well after the DocumentCompleted event is fired, making the event close to useless in my case.

所以目前我有类似...

So currently I have something like...

while (webBrowser.Document?.GetElementById("id")?.GetAttribute("classname") != "class")
{
    Application.DoEvents();
    Thread.Sleep(1);
}

现在我已经在多个地方读到DoEvents()是邪恶的,并且会引起很多问题,因此我考虑将其替换为Task.Delay()这样的

Now I've read in multiple places that DoEvents() is evil and can cause lots of issues, so I thought about replacing it with Task.Delay() as such:

while (webBrowser.Document?.GetElementById("id")?.GetAttribute("classname") != "class")
{
    await Task.Delay(10);
}

所以我的问题是,除了显而易见的事实,即Thread.Sleep()会在1ms内阻塞事件,并且Task.Delay()在上面的示例中设置了更大的延迟,这两种方法之间的实际区别是什么,哪个更好,为什么?

So my question is, other than the obvious facts that the Thread.Sleep() will block events for 1ms and that the Task.Delay() has a bigger delay set in the example above, what are the actual differences between doing the two approaches, which is better and why?

PS:,请坚持这个问题,尽管我不一定会想到其他方法,以通过使用其他方法来解决WebBrowser控件本身的问题(想到了js注入),并不是要回答这个问题的地方,这个问题是关于这两位代码有何不同以及哪个会更好.

PS: Please stick to the question, while I wouldn't necessarily mind other ideas on how to fix the WebBrowser control issue itself by using something else (js injection comes to mind), this is not the place to answer that, this question is about how these two bits of code differ and which would be considered better.

推荐答案

两种方法之间的实际区别是什么?这更好,为什么?

what are the actual differences between doing the two approaches, which is better and why?

等待期间处理消息的方式不同.

The differences are in how messages are processed while waiting.

DoEvents将安装嵌套的消息循环;这意味着您的堆栈将具有(至少)两个消息处理循环.这引起了重入问题,这是IMO避免DoEvents的最大原因.嵌套消息循环应处理的事件类型有无穷无尽的问题,因为该决策的两面都有死锁,并且没有适用于所有应用程序的解决方案.有关消息泵送的深入讨论,请参见经典的 CLR中的公寓和抽水博客文章.

DoEvents will install a nested message loop; this means that your stack will have (at least) two message processing loops. This causes reentrancy issues, which IMO is the biggest reason to avoid DoEvents. There's endless questions about which kinds of events the nested message loop should process, because there's deadlocks on both sides of that decision, and there's no solution that's right for all applications. For an in-depth discussion of message pumping, see the classic Apartments and Pumping in the CLR blog post.

相反,await返回.因此,它不使用嵌套的消息循环来处理消息.它只允许原始消息循环来处理它们.当async方法准备好恢复时,它将向消息循环发送一条特殊消息,该消息循环将继续执行async方法.

In contrast, await will return. So it doesn't use a nested message loop to process messages; it just allows the original message loop to process them. When the async method is ready to resume, it will send a special message to the message loop that resumes executing the async method.

因此,await启用了并发,但没有DoEvents固有的所有真正困难的重入问题. await绝对是上乘的方法.

So, await enables concurrency but without all the really difficult reentrancy concerns inherent in DoEvents. await is definitely the superior approach.

基本上,有一个持续的论点是DoEvents()是更好的",因为它不消耗线程池中的任何线程

Basically there's an ongoing argument that DoEvents() is "better" because it doesn't consume any threads from the thread pool

好吧,await也不消耗线程池中的任何线程.景气.

Well, await doesn't consume any threads from the thread pool, either. Boom.

这篇关于Application.DoEvents与循环等待a Task.Delay的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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