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

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

所以目前我有类似...

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

现在,我在多个地方都读到DoEvents()是邪恶的,并且会引起很多问题,因此我考虑将其替换为Task.Delay(),例如:
while (webBrowser.Document?.GetElementById("id")?.GetAttribute("classname") != "class")
{
    await Task.Delay(10);
}

因此,我的问题是,除了上面的示例中Thread.Sleep()会阻塞事件1ms以及Task.Delay()具有更大的延迟这一显而易见的事实之外,两种方法之间的实际区别是什么,哪个更好,为什么?

PS:请坚持这个问题,虽然我不一定会介意关于如何通过使用其他东西来解决WebBrowser控件本身的其他想法(想到了js注入(inject)),但这不是回答这个问题的地方问题是这两位代码有何不同,哪个会更好。

最佳答案



区别在于等待时如何处理消息。
DoEvents将安装一个嵌套的消息循环;这意味着您的堆栈将具有(至少)两个消息处理循环。这是causes reentrancy issues,这是IMO避免DoEvents的最大原因。关于嵌套消息循环应处理哪种事件,存在无休止的问题,因为该决策的两面都有死锁,并且没有适合所有应用程序的解决方案。有关消息泵送的深入讨论,请参见经典的Apartments and Pumping in the CLR博客文章。

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

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



好吧,await也不消耗线程池中的任何线程。繁荣。

关于c# - Application.DoEvents与循环等待a Task.Delay,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35188070/

10-11 22:32
查看更多