Programmablauf

  • Allgemein

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Programmablauf

    hi,

    ich habe ein ganz allgemeines Problem:

    stellen wir uns vor, ich habe eine Liste mit vielen ITEMs. Wenn der Benutzer auf Start klickt, arbeitet das Programm die Liste von oben ab. Es werden viele Sub's und Function's je Listpunkt durchlaufen. Dabei rufen sich die Bearbeitungs-Routinen mit Ergebnissen der vorherigen Routine selber auf.
    Zusätzlich gibt es aber auch ein "Abbrechen" Button wo der Benutzer die Möglichkeit hätte (oder haben soll), die umfangreiche Abarbeitung sofort(!) zu beenden.
    Frage ist nun: wie und an welcher Stelle kann ich die Abbrechen-Funktion elegant einbauen? In der ursprünglichen Liste-Schleife hilft mir nur wenig, da das Programm ja gerade in einer beliebigen Funktion hängen kann (mit Rückgabewert zur Weiterverarbeitung).
    Meine Idee ist bisher, in jeder Unterroutine am Anfang eine Abfrage auf "Ist Abbrechen" zu schreiben, um dann Rückwärts wieder bis zum Startknopf zu kommen. Leider sehr umständlich ...

    Hat jemand eine bessere Idee?
    Willkommen im Forum. :thumbup:
    Du hast ein sehr anspruchsvolles Thema für einen erstren Beitrag.
    Bei einem Break kannst Du eine globale Variable setzen, und wenn Du bei Deinen Prozeduren den Returnvalue / Fehlercode zurückgibst, kannst Du testen, ob Break aktiv ist.
    Mit einem Fehlercode sollte dann die nächste Prozedur nicht mehr aufgerufen werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Hoernchen schrieb:

    Zusätzlich gibt es aber auch ein "Abbrechen" Button wo der Benutzer die Möglichkeit hätte (oder haben soll), die umfangreiche Abarbeitung sofort(!) zu beenden.

    Ohne MultiThreading geht das nicht.
    Du kannst einen Button ühaupt nicht klicken, wenn die Programm-Ausführung sich in einer Methode befindet, die iwas abarbeitet. (Natürlich kannste drauf rumklicksen, nur das Prog kann nicht reagieren.)

    Wie Rod sagt: Ein anspruchsvolles Thema: AsyncWorker - CodeProject
    Ja... aber das ist doch genau das, was ich im Augenblick auch mache. Klickt der Benutzer auf "Abbrechen" wird eine globale Variable auf True gesetzt. Diese Variable kann ich in jeder Unterroutine zu Anfang prüfen (auf True). Muss dann aber auch jeweils zusätzliche Rückgabewerte "erfinden" damit die aufrufende Funktion merkt, dass kein Weiterarbeiten erwünscht ist.
    Früher in VB6 war es denkbar einfach: man konnte ein benutzerdefinierten Fehler auslösen und alle Unterroutinen ohne "Fehlerbearbeitung" (On Error Goto IRGENDWAS) schreiben. VB6 ist dann von selbst Rückwärts durch alle Routinen gelaufen um eine Fehlerbearbeitung zu suchen. Diese stand dann eben erst in "StartButton_Click"
    Bei uns wird so ge-Workflow-t:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Enum ReturnValues
    2. eOK
    3. eFehler1
    4. eFehler2
    5. eFehler3
    6. End Enum
    7. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    8. Dim result As ReturnValues = ReturnValues.eOK
    9. If result = ReturnValues.eOK Then
    10. result = Proc1()
    11. End If
    12. If result = ReturnValues.eOK Then
    13. result = Proc2()
    14. End If
    15. If result = ReturnValues.eOK Then
    16. result = Proc3()
    17. End If
    18. If result = ReturnValues.eOK Then
    19. result = Proc4()
    20. End If
    21. End Sub
    Sobald irgendwo ein Fehler auftritt, wird die weitere Abarbeitung abgebrochen und das result kann ausgewertet werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Nicht ganz... innerhalb der Listschleife werden verschieden WebSeiten aufgerufen. Damit die Programmausführung erst weiter geht wenn die Webseite vollständig vorliegt sind "Warteschleifen" eingebaut die mit "doevents" gefüttert sind. Also der Abbrechen Button bzw. die globale Variable wird schon gesetzt und kann auch abgefragt werden.

    Hoernchen schrieb:

    die mit "doevents" gefüttert sind.
    Das hatte ich befürchtet. ;(
    Das ist sehr suboptimal. Das gehört in einen Thread oder BackGroundWorker.
    Kannst Du mal, wenigstens in Grundzügen, Deinen Code posten?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Hoernchen schrieb:

    innerhalb der Listschleife werden verschieden WebSeiten aufgerufen. Damit die Programmausführung erst weiter geht wenn die Webseite vollständig vorliegt sind "Warteschleifen" eingebaut die mit "doevents" gefüttert

    ->
    Await (New WebClient()).DownloadStringTaskAsync(foo)

    Einfach sauber klar = Net FW 4.5 (oder halt 4.0 mit Async Erweiterung)
    ... aber der Ansatz mit einem seperaten Task klingt mir bisher sehr brauchbar.
    Ich versuche mal die Idee umzusetzen. Danke soweit.

    Vielleicht zum Verständnis noch mal ein (fiktivers) Beispiel:
    eine Liste mit 100 Firmen-Webseiten die verarbeitet werden sollen und ein Button "Feierabend". Klickt der Mitarbeiter (weil 17:00 Uhr) auf Feierabend soll die weitere Verarbeitung beendet werden (Programm aber nicht einfach auf END setzen)
    Dann sollte das Flag nach Fertigstellung jedes Listen-Items abgefragt und ausgewertet werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    nee ist klar ... aber das würde nicht der Zielsetzung entsprechen: SOFORT(!) abbrechen. Nach jedem ITEM-Durchlauf wäre schon zu spät (ist wahrscheinlich ein sehr spezielles Problem).
    Aber richtig ist soweit, dass ich genau bis an diese Stelle eben zurück will und dann die Schleife sauber verlassen kann.
    Evtl ein Job für TPL Dataflow?

    VB.NET-Quellcode

    1. Imports System.Threading.Tasks.Dataflow
    2. Public Class Form1
    3. Dim t As New TransformBlock(Of String, String)(Function(s As String) As String
    4. Threading.Thread.Sleep(5000)
    5. Return s
    6. End Function)
    7. Dim a As New ActionBlock(Of String)(AddressOf Output)
    8. Private Sub Output(ByVal s As String)
    9. Debug.Print(s)
    10. End Sub
    11. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    12. t.Post("Hallo")
    13. End Sub
    14. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    15. unlink.Dispose()
    16. End Sub
    17. Dim unlink As IDisposable
    18. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    19. unlink = t.LinkTo(a)
    20. End Sub
    21. End Class

    Hoernchen schrieb:

    ein Button "Feierabend".

    Hoernchen schrieb:

    aber das würde nicht der Zielsetzung entsprechen: SOFORT(!) abbrechen.
    Das sind also 2 Paar Schuhe.
    Nach einem Job abbrechen ist definiert aufhören. Rechner aus, und morgen früh, Rechner an, geht es an derselben Stelle weiter.
    Sofort abbrechen ist ggf. mit Datenverlust verbunden. Da muss der angefangene DAtensatz und unterbrochene Ablauf ggf. noch einmal angetriggert werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    mit SOFORT abbrechen meinte ich zunächst nur die augenblickliche Abarbeitung eines ITEM's.
    Nehmen wir also an, ein ITEM in der Liste benötigt bis zur kompletten Abarbeitung 20 verschieden Unterroutinen (die sich selbst aufrufen und Ergebnisse untereinander austauschen). Ist "Abbrechen" eingetreten will ich sauber (ohne Weiterverarbeitung) zur ListSchleife zurückkehren.
    Klar, Deine Aufgabe.
    Wie lange dauert denn die vollständige Abarbeitung eines Listen-Items?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    da zur kompletten Abarbeitung eines ITEM's auch das Auslesen von WebSeiten dazu gehört ist die Verarbeitungszeit unterschiedlich.

    Übrigens ... schönes Beispiel: Nehmen wir an, bei der Bearbeitung eines ITEM's wird die WebSeite XYZ geöffnet. Auf dieser befindet sich nun ein Virus (was mein Programm erkennt ... rein fiktiv). Natürlich soll dann keine weitere Aktion mit diesem ITEM durchgefürt werden (eben abbrechen). Also sofort zurück zur Liste und den nächsten ITEM bearbeiten.

    Aber ich denke, der Vorschlag, die Bearbeitung eines ITEM's komplett in einem eigenen Task durchzuführen und diesen gegebenenfalls zu killen (Datenverlust würde ja keine Rolle spielen) ist sehr brauchbar. Muss ich mir mal in Ruhe ansehen wie man das programmiert ... noch keine Erfahrung. Aber man lernt ja gerne hinzu.
    Bei Abrufen von WebSites würde ich sogar viele Threads empfehlen. Die Threads machen ja eiglich nix, die warten ja nur, bis eine Antwort kommt.

    Das braucht nichtmal viel Resource zu belegen, wenn man die vorgesehenen asynchronen Methoden verwendet.

    In Multi-Tutorial habich sowas mal umgesetzt - aber ist ziemlich anspruchsvoll.

    Hoernchen schrieb:

    Ist "Abbrechen" eingetreten will ich sauber (ohne Weiterverarbeitung) zur ListSchleife zurückkehren.

    Im Zweifel machst du halt eh keinen "linearen" Workflow und damit brauchst du auch nicht "zurückkehren"

    @EDR:
    Bei Abrufen von WebSites würde ich sogar viele Threads empfehlen.

    Eher viele asynchrone Tasks ;)