2013-07-02 14 views
21

Ich bin ein Anfänger Programmierer, also könnte ich hier völlig falsch liegen, aber dieses Problem bugs mich mehr als es sollte.InvokeRequired blind verwendet nicht einfach schlechte Praxis?

Dies ist eigentlich ein Follow-up von this Frage.

Die angenommene Antwort war, dass Sie InvokeRequired aufrufen müssen, um einige Overhead zu vermeiden, da Sie die Möglichkeit haben, bereits auf dem UIhread zu arbeiten.

In der Theorie stimme ich zu, dass es etwas Zeit sparen könnte. Nach einigen Tests habe ich herausgefunden, dass die Verwendung von Invoke ungefähr doppelt so lange dauert wie der normale Aufruf einer Operation (Tests wie das n-fache Setzen des Textes einer Beschriftung oder das Platzieren einer sehr, sehr großen Zeichenkette in einer RichTextBox).

Aber! Dann gibt es Übung.

MSDN-Dokumentation sagt:

Diese Eigenschaft verwendet werden kann, um festzustellen, ob Sie ein invoke-Methode aufrufen müssen, die nützlich sein können, wenn Sie nicht wissen, was Thread eine Kontrolle besitzt.

In den meisten Fällen Sie tun wissen, wenn Sie versuchen, eine Kontrolle von einem anderen Thread zuzugreifen. Tatsächlich ist die einzige Situation, an die ich denken kann, wenn auf das Steuerelement über eine Methode zugegriffen wird, die sowohl vom Thread X als auch vom Eigentümer-Thread aufgerufen werden kann. Und das ist für mich eine sehr unwahrscheinliche Situation.

Und selbst wenn Sie wirklich nicht wissen, welcher Thread versucht, das Steuerelement zu manipulieren, gibt es die Tatsache, dass der UI-Thread nicht so häufig aktualisiert werden muss. Alles zwischen 25-30 fps sollte für Ihre GUI in Ordnung sein. Und die meisten Änderungen, die in den UI-Steuerelementen vorgenommen werden, benötigen weit weniger als Millisekunden. Wenn ich also richtig verstehe, ist das einzige Szenario, in dem Sie prüfen müssen, ob ein Aufruf erforderlich ist, wenn Sie nicht wissen, welcher Thread auf das Steuerelement zugreift und wann das GUI-Update mehr als 40 ms dauert.

Dann gibt es die Antwort auf this Frage ich fragte http://programmers.stackexchange.com. Was besagt, dass Sie nicht mit vorzeitigen Optimierung beschäftigt sein sollten, wenn Sie es nicht brauchen. Vor allem, wenn es die Lesbarkeit von Code opfert.

So bringt mich das auf meine Frage: sollte nicht einfach aufrufen verwenden, wenn Sie einen anderen Thread kennen eine Steuer zugreift und nur, wenn Sie Ihre UI-Thread wissen, dass Stück Code zugreifen können und Sie finden dass es schneller laufen sollte, dass Sie prüfen sollten, ob ein Invoke erforderlich ist?

PS: Nach dem Korrekturlesen meiner Frage klingt es wirklich so, als würde ich schimpfen. Aber eigentlich bin ich nur neugierig, warum InvokeRequired anscheinend von vielen mehr-erfahrenen-als-ich-Programmierern überstrapaziert wird.

+4

Gut gemacht auf Ihrem Beitrag. – ChiefTwoPencils

+3

Im Allgemeinen stimme ich zu - wenn Sie erwarten, dass ein Anruf in einem Nicht-UI-Thread eingeht, hat es wenig Sinn, den Code mit InvokeRequired zu überladen. –

+0

@DanielHilgarth (glaube ich) er nicht, wenn Sie den Thread kennen, müssen Sie nicht den Thread überprüfen, wenn Sie den Thread nicht kennen, sollten Sie überprüfen. –

Antwort

9

Sie nehmen die Dinge hier aus dem Zusammenhang. Die erste Frage you linked verknüpfte eine andere Frage, die speziell über das Schreiben einer thread-sicheren-Methode zum Zugriff auf ein UI-Steuerelement ging.

Wenn Sie keinen Thread-sicheren Zugriff auf ein UI-Steuerelement benötigen, weil Sie wissen, dass Sie es nicht von einem anderen Thread aktualisieren, dann sollten Sie diese Technik sicherlich nicht verwenden. Aktualisieren Sie einfach Ihre UI-Steuerung, ohne InvokeRequired oder Invoke zu verwenden.

Auf der anderen Seite, wenn der Anruf immer in einem anderen Thread als der UI-Thread stammt, verwenden Sie einfach Invoke, ohne vorher für InvokeRequired zu überprüfen.

Dies führt zu drei einfachen Regeln:

  1. Wenn Sie die Steuerung nur aus dem UI-Thread aktualisieren, verwendet weder InvokeRequired noch Invoke
  2. Wenn Sie die Steuerung aktualisieren, die von einem anderen Thread als der UI-Thread , nur Invoke verwenden.
  3. Wenn Sie das Steuerelement sowohl vom UI-Thread als auch von anderen Threads aktualisieren, verwenden Sie Invoke in Kombination mit InvokeRequired.
+0

Ich stimme zu, sollte es aber nicht sein: "3. Wenn Sie das Steuerelement sowohl vom UI-Thread als auch von anderen Threads aktualisieren und alles wie erwartet funktioniert, verwenden Sie Invoke. 4.Wenn Sie das Steuerelement sowohl vom UI-Thread als auch von anderen aktualisieren threads und nur mit invoke ist zu langsam, verwenden Sie Invoke in Kombination mit InvokeRequired. "? – Jordy

+2

@Jordy: Ich würde das nicht tun. Nicht wegen vorzeitiger Optimierung, sondern weil die Kombination von InvokeRequired und Invoke ein festes Muster in einem Szenario ist, in dem der aufrufende Thread alles sein kann. –

8

In der Praxis neigen Menschen dazu, die gleiche Methode sowohl aus dem fremden als auch aus dem eigenen Thread aufzurufen. Das übliche Muster ist, dass die Methode selbst bestimmt, ob der Thread der besitzende Thread ist. Wenn dies der Fall ist, wird der Folgecode ausgeführt. Wenn dies nicht der Fall ist, ruft die Methode selbst Invoke dieses Mal auf.

Ein Vorteil davon ist, dass es den Code kompakter macht, wie Sie eine Methode im Zusammenhang mit der Operation statt zwei haben.

Ein anderer und wahrscheinlich wichtigerer Vorteil ist, dass es die Wahrscheinlichkeit verringert, dass die Cross Thread-Ausnahme ausgelöst wird. Wenn beide Methoden zu irgendeinem Zeitpunkt verfügbar wären und beide Threads eines der beiden auswählen könnten, bestünde die Chance, dass ein scheinbar legitimer Methodenaufruf eine Ausnahme auslöst. Auf der anderen Seite, wenn es nur eine Methode gibt, die sich an die Situation anpasst, bietet es eine sicherere Schnittstelle.

+0

Aber in den meisten Codebeispielen, die ich sehe, wird es als SetTextBox (string text) verwendet. Aber müssen Methoden wie diese nicht schon das Offensichtliche machen, dass Sie versuchen, von außerhalb des UI-Threads darauf zuzugreifen?Scheint mir, wenn Sie eine TextBox aus dem ui-Thread ändern möchten, würden Sie wahrscheinlich nur TextBox.Text aufrufen – Jordy

+0

@Jordy Der Punkt ist, dass es Ihnen nicht kümmert, ob Sie auf dem UI-Thread beim Aufruf sind die Methode (auch wenn Sie an einem bestimmten Anrufpunkt sicher wären). Es überlässt den Check vollständig der Methode selbst. Methoden wie diese zu machen, bedeutet nur, dass Sie sich in einem * möglichen * Cross-Thread-Szenario befinden, nicht dass Sie zu irgendeinem Zeitpunkt * unbedingt * vom falschen Thread aus anrufen. –

+0

Ich denke, ich fange an zu sehen, dass du ein Punkt bist, aber wenn du deinen Code threadsicher machen willst, sollte etwas wie das Sperren nicht wie eine bessere Lösung aussehen? – Jordy

Verwandte Themen