3 回答

TA貢獻(xiàn)1799條經(jīng)驗(yàn) 獲得超9個(gè)贊
DoEvents()很危險(xiǎn)。但我敢打賭,你每天都會(huì)做很多危險(xiǎn)的事情。就在昨天,我引爆了一些爆炸裝置(未來(lái)的讀者:請(qǐng)注意相對(duì)于某個(gè)美國(guó)假期的原始發(fā)布日期)。小心,我們有時(shí)可以解釋危險(xiǎn)。當(dāng)然,這意味著了解并了解危險(xiǎn)是什么:
重新進(jìn)入的問(wèn)題。這里實(shí)際上有兩個(gè)危險(xiǎn):
這里的部分問(wèn)題與調(diào)用堆棧有關(guān)。如果在循環(huán)中調(diào)用.DoEvents(),該循環(huán)本身處理使用DoEvents()的消息,依此類推,則會(huì)得到一個(gè)非常深的調(diào)用堆棧。很容易過(guò)度使用DoEvents()并意外填滿調(diào)用堆棧,從而導(dǎo)致StackOverflow異常。如果你只在一兩個(gè)地方使用.DoEvents(),你可能還可以。如果它是您長(zhǎng)時(shí)間運(yùn)行過(guò)程中的第一個(gè)工具,那么您可以輕松地在這里遇到麻煩。即使在錯(cuò)誤的地方使用一次也可以使用戶強(qiáng)制執(zhí)行stackoverflow異常(有時(shí)只需按住enter鍵),這可能是一個(gè)安全問(wèn)題。
有時(shí)可以在調(diào)用堆棧上找到相同的方法兩次。如果你沒(méi)有記住這個(gè)方法(提示:你可能沒(méi)有),那么可能會(huì)發(fā)生不好的事情。如果傳入方法的所有內(nèi)容都是值類型,并且不依賴于方法之外的東西,那么您可能沒(méi)問(wèn)題。但除此之外,您需要仔細(xì)考慮如果在調(diào)用.DoEvents()之前將控制權(quán)返回給您之前再次運(yùn)行整個(gè)方法會(huì)發(fā)生什么。您的方法之外的哪些參數(shù)或資源可能會(huì)被修改為您沒(méi)想到的?您的方法是否更改了任何對(duì)象,其中堆棧上的兩個(gè)實(shí)例可能都在同一個(gè)對(duì)象上?
性能問(wèn)題。DoEvents()可以給出多線程的錯(cuò)覺(jué),但它不是真正的多線程。這至少有三個(gè)真正的危險(xiǎn):
當(dāng)您調(diào)用DoEvents()時(shí),您將現(xiàn)有線程的控制權(quán)交還給消息泵。消息泵可能反過(guò)來(lái)控制其他東西,而其他東西可能需要一段時(shí)間。結(jié)果是你的原始操作可能需要更長(zhǎng)的時(shí)間來(lái)完成,而不是它本身的線程永遠(yuǎn)不會(huì)產(chǎn)生控制,絕對(duì)比它需要的更長(zhǎng)。
重復(fù)工作。因?yàn)橛锌赡馨l(fā)現(xiàn)自己運(yùn)行兩次相同的方法,并且我們已經(jīng)知道這個(gè)方法很昂貴/長(zhǎng)時(shí)間運(yùn)行(或者你首先不需要DoEvents()),即使你考慮了所提到的所有外部依賴性因此沒(méi)有不良的副作用,你可能仍然會(huì)重復(fù)很多工作。
另一個(gè)問(wèn)題是第一個(gè)問(wèn)題的極端版本:潛在的僵局。如果你的程序中的其他內(nèi)容取決于你的進(jìn)程完成,并且會(huì)阻塞直到它完成,并且那個(gè)東西被來(lái)自DoEvents()的消息泵調(diào)用,你的應(yīng)用程序?qū)⒈豢ㄗ〔⒆兊脽o(wú)法響應(yīng)。這可能聽(tīng)起來(lái)很牽強(qiáng),但在實(shí)踐中,意外地做起來(lái)非常容易,并且以后很難找到并調(diào)試崩潰。這是您在自己的計(jì)算機(jī)上可能遇到的一些掛起應(yīng)用程序情況的根源。
可用性問(wèn)題。這些副作用是由于不能正確解釋其他危險(xiǎn)造成的。這里沒(méi)有什么新東西,只要你適當(dāng)?shù)乜雌渌胤健?/p>
如果你能確定你已經(jīng)解決了所有這些問(wèn)題,那就繼續(xù)吧。但實(shí)際上,如果DoEvents()是您首先要解決的UI響應(yīng)/更新問(wèn)題,那么您可能無(wú)法正確解決所有這些問(wèn)題。如果它不是你看的第一個(gè)地方,還有足夠的其他選項(xiàng),我會(huì)質(zhì)疑你是如何考慮DoEvents()的。
現(xiàn)實(shí)情況是,大多數(shù)情況下,至少在.Net世界中,BackgroundWorker組件幾乎一樣容易,至少一次完成一次或兩次,它將以安全的方式完成工作。最近,異步/等待模式或使用a Task
可以更加有效和安全。

TA貢獻(xiàn)1836條經(jīng)驗(yàn) 獲得超13個(gè)贊
我可能錯(cuò)了,但在我看來(lái)DoDragDrop
并且TrackPopupMenu
是相當(dāng)特殊的情況,因?yàn)樗鼈兘庸芰薝I,因此沒(méi)有重入問(wèn)題(我認(rèn)為這是人們DoEvents
稱之為“邪惡”的主要原因)。
就個(gè)人而言,我認(rèn)為將某個(gè)功能視為“邪惡”并不合適 - 而是解釋陷阱,以便人們可以自行決定。在DoEvents
極少數(shù)情況下,使用它仍然是合理的,例如在顯示模態(tài)進(jìn)度對(duì)話框時(shí),用戶無(wú)法與UI的其余部分進(jìn)行交互,因此不會(huì)出現(xiàn)重入問(wèn)題。
當(dāng)然,如果用“邪惡”來(lái)表示“你不應(yīng)該在沒(méi)有完全理解陷阱的情況下使用的東西”,那么我同意這DoEvents
是邪惡的。

TA貢獻(xiàn)1765條經(jīng)驗(yàn) 獲得超5個(gè)贊
回到16位Windows時(shí)代,當(dāng)每個(gè)任務(wù)共享一個(gè)線程時(shí),保持程序在緊密循環(huán)中響應(yīng)的唯一方法是DoEvents。這種非模態(tài)用法不支持線程。這是一個(gè)典型的例子:
' Process image
For y = 1 To height
For x = 1 to width
ProcessPixel x, y
End For
DoEvents ' <-- DON'T DO THIS -- just put the whole loop in another thread
End For
對(duì)于模態(tài)事物(如跟蹤彈出窗口),它可能仍然可以。
- 3 回答
- 0 關(guān)注
- 799 瀏覽
添加回答
舉報(bào)