Multitasking ist gefragt

  • Ich möchte eine Funktion ausführen (lade_etwas()), die eine längere Zeit (ca. 30s) läuft. Dabei soll das Skript aber weiter laufen.
    Wie mache ich das, ohne dass das Skript einfriert?

    Es wird immer getestet (etwas_geladen()) ob obige Funktion gestartet ist, dann soll man z.B. auf einen Knopf innerhalb von 15s drücken, damit etwas gesendet wird (sende_etwas()).
    Wenn die man den Knopf drückt oder die Zeit abläuft soll die oben genannte Funktion wieder gestartet werde.
    Dafür habe ich einen Timer verwendet, ist das soweit ok?

    Dann möchte ich noch, dass alle 10s etwas anderes abgefragt wird (frage_ab()).
    Das auch wieder mit einem Timer, macht das Sinn?

    Hier meine Beispiel Fkt.
    [autoit]

    #include <GuiConstantsEx.au3>
    global $bLadeEtwas

    [/autoit] [autoit][/autoit] [autoit]

    lade_etwas()

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate("titel", -1, -1, 100, 100)
    $b_start = GUICtrlCreateButton("Starten", 10, 10, 80, 30)

    [/autoit] [autoit][/autoit] [autoit]

    gui()

    [/autoit] [autoit][/autoit] [autoit]

    ; die Funktionen

    [/autoit] [autoit][/autoit] [autoit]

    func lade_etwas()
    ; etwas das ca. 30s am Stück läuft, Ergebniss gibt es erst, wenn es fertig ist
    $bLadeEtwas = true
    ;sleep(3000)
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func etwas_geladen()
    ; testen ob lade_etwas() schon geladen hat
    if $bLadeEtwas = true then
    return true
    else
    return false
    endif
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func sende_etwas()
    ; einfach etwas senden oder speichern
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func frage_ab()
    ; frage etwas ab
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func gui()
    local $bGeladen = false, $iTimer = TimerInit(), $iZeit = TimerInit(), $iZeit2 = 0

    GUISetState(@SW_SHOW)

    while true
    switch GUIGetMsg()
    case $GUI_EVENT_CLOSE
    exit

    case $b_start
    if $bGeladen = true then
    sende_etwas()
    $bGeladen = false
    $iZeit2 = 0
    lade_etwas() ; neustarten
    MsgBox(0, "", "sende_etwas!")
    else
    MsgBox(0, "", "Tue nichts")
    endif
    endswitch

    ; alle 10s etwas abfragen
    if Mod(TimerDiff($iTimer), 10*1000) < 1000 then
    ; kleiner als 100, weil man nie genau die Milisekunde trifft
    frage_ab()
    endif

    ; wenn etwas_geladen() = false testen, bis true
    if $bGeladen = false then
    $bGeladen = etwas_geladen()
    endif

    if $bGeladen = true then
    ; neue Zeit setzen, wenn neues true
    if $iZeit2 = 0 then
    $iZeit2 = TimerDiff($iZeit)
    MsgBox(0, "", "etwas_geladen = true")

    ; wenn die Zeit verstrichen ist
    elseif $iZeit2+15*1000 < TimerDiff($iZeit) then
    $bGeladen = false
    $iZeit2 = 0
    MsgBox(0, "", "etwas_geladen = Zeit vorbei")
    lade_etwas() ; neustarten
    endif
    endif
    wend
    endfunc

    [/autoit]

    Mir geht es vor allem um die Fkt. lade_etwas(), die lange etwas ladet (Zeit ist dynamisch).
    Ich habe auch schon überlegt ob das ein anders Skript ausführt und an dieses, wenn fertig, das Ergebnis übergibt!?

  • also die einfachste idee die mir jetzt so auf die schnelle eingefallen ist wäre, wenn du den teil in "lade_etwas()" einfach zu einer exe datei machst und die dann einfach startest. so wird der teil nur einmal kurz aufgerufen und läuft parallel zum hauptscript ;) ist jetzt natürlich nur so eine idee....keine ahnung ob das bei deinem programm gehen würde ;)

  • So, jetzt läuft auch das Beispiel.

    also die einfachste idee die mir jetzt so auf die schnelle eingefallen ist wäre, wenn du den teil in "lade_etwas()" einfach zu einer exe datei machst und die dann einfach startest. so wird der teil nur einmal kurz aufgerufen und läuft parallel zum hauptscript ;) ist jetzt natürlich nur so eine idee....keine ahnung ob das bei deinem programm gehen würde ;)

    Ja, würde gehen, hab ich ja auch als Möglichkeit schon in Betracht gezogen, aber das wird komplizierter, als wenn alles in einem Skript laufen würde ...

    Ich würde AdlibRegister nehmen.

    Danke, das kann ich für etwas_geladen() und frage_ab() verwenden!

  • Ich würde AdlibRegister nehmen.

    AdlibRegister ruft lediglich die definierte Funktion periodisch auf, während die Funktion aber läuft wird das restliche Script trotzdem pausiert.

    Autoit ist von Haus auf nicht multithreadingfähig. Der einfachstes Weg ist wie RedHead schon gesagt hat da Auslagern in eine seperate exe.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

  • .... Oder, wenn man "Platz sparen" will, mit Startparametern den Code ausführen zu lassen, wenn ihr wisst wie ich das meine. So kann man sich die zusätzliche Exe sparen, da man dann nur 1 Script hat ;)

    lg chess

    Edit:
    Mal ein Beispiel, um zu verdeutlichen wie ich das meine.

    Variante 1 (2 *.exe-Dateien):

    Programm_1.exe
    [autoit]


    Run("Programm_2.exe")

    [/autoit]
    Programm_2.exe
    [autoit]


    MsgBox(0,"","Erfolg!")

    [/autoit]


    Variante 2(1 *.exe-Datei mit Startparametern):

    Programm.exe
    [autoit]


    If $CmdLine[0] = 0 Then
    ShellExecute(@ScriptName,"Nachricht")
    ElseIf $CmdLine[1] = "Nachricht" Then
    MsgBox(0,"","Erfolg!")
    EndIf

    [/autoit]


    Müsste klappen, kann aber sein dass es nicht so klappt, nur eben im Forumeditor geschrieben... ;)
    Noch ein Vorteil: Variante 2 ist dynamisch, sprich es klappt auch, wenn die *.exe umbenannt wird.

    lg chess

  • Irgendwie wird der $bGeladen = true nicht von der AdlibRegister-Fkt. auf den Rest übertragen!?

    Beispiel Skript 2
    [autoit]

    #include <GuiConstantsEx.au3>
    global $bLadeEtwas, $bGeladen = false

    [/autoit] [autoit][/autoit] [autoit]

    lade_etwas()

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate("titel", -1, -1, 100, 100)
    $b_start = GUICtrlCreateButton("Starten", 10, 10, 80, 30)

    [/autoit] [autoit][/autoit] [autoit]

    AdlibRegister("etwas_geladen", 500)
    AdlibRegister("frage_ab", 10*1000)
    gui()

    [/autoit] [autoit][/autoit] [autoit]

    ; die Funktionen

    [/autoit] [autoit][/autoit] [autoit]

    func lade_etwas()
    ; etwas das ca. 30s am Stück läuft, Ergebniss gibt es erst, wenn es fertig ist
    $bLadeEtwas = true
    ;sleep(3000)
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func etwas_geladen()
    ; testen ob lade_etwas() schon geladen hat
    if $bLadeEtwas = true and $bGeladen = false then
    ; ...
    MsgBox(0, "", "etwas_geladen setze true")
    $bGeladen = true
    endif
    ;MsgBox(0, "", "etwas_geladen")
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func sende_etwas()
    ; einfach etwas senden oder speichern
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func frage_ab()
    ; frage etwas ab
    MsgBox(0, "", "frage_ab!")
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func gui()
    local $bGeladen = false, $iTimer = TimerInit(), $iZeit = TimerInit(), $iZeit2 = 0

    GUISetState(@SW_SHOW)

    while true
    switch GUIGetMsg()
    case $GUI_EVENT_CLOSE
    exit

    case $b_start
    if $bGeladen = true then
    sende_etwas()
    $bGeladen = false
    $iZeit2 = 0
    lade_etwas() ; neustarten
    MsgBox(0, "", "sende_etwas!")
    else
    MsgBox(0, "", "Tue nichts")
    endif
    endswitch

    if $bGeladen = true then
    ; neue Zeit setzen, wenn neues true
    if $iZeit2 = 0 then
    $iZeit2 = TimerDiff($iZeit)
    MsgBox(0, "", "etwas_geladen = true")

    ; wenn die Zeit verstrichen ist
    elseif $iZeit2+15*1000 < TimerDiff($iZeit) then
    $bGeladen = false
    $iZeit2 = 0
    MsgBox(0, "", "etwas_geladen = Zeit vorbei")
    lade_etwas() ; neustarten
    endif
    endif
    wend
    endfunc

    [/autoit]

    .... Oder, wenn man "Platz sparen" will, mit Startparametern den Code ausführen zu lassen, wenn ihr wisst wie ich das meine. So kann man sich die zusätzliche Exe sparen, da man dann nur 1 Script hat ;)

    Hm, dass das Skript sich dann selbst noch einmal mit Startparameter öffnet, aber dann etwas ganz anderes macht.
    Also mit Parameter lade_etwas() ausführt und ohne Parameter GUI und den Rest ausführt!?
    Kann das nicht zu Problemen führen, wenn das selbe Programm zweimal aktiv ist?
    Die Idee ist aber echt gut :)

  • die idee ist gut! und einfach umzusetzen:

    [autoit]


    If $CmdLine[0]>0 AND $CmdLine[1] = "load" Then
    lade_etwas ()
    else
    Run (@ScriptFullPath &" load")
    GUICreate("titel", -1, -1, 100, 100)
    $b_start = GUICtrlCreateButton("Starten", 10, 10, 80, 30)
    EndIf
    #####################################################
    If $CmdLine[0] > 0 Then
    Switch $CmdLine[1]
    Case "two"
    Run (@ScriptFullPath & " three")
    MsgBox (0, "Multithreading4AutoIt", "2nd Thread")
    Case "three"
    MsgBox (0, "Multithreading4AutoIt", "3rd Thread")
    EndSwitch
    Else
    Run (@ScriptFullPath & " two")
    MsgBox (0, "Multithreading4Autoit", "1st Thread")
    EndIf

    [/autoit]


    muss übrigens compiliert sein, um zu funktionieren

    MfG. tobi_girst

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »tobi_girst« (Morgen, 25:63)

    2 Mal editiert, zuletzt von tobi_girst (1. Mai 2012 um 18:48)

  • Danke, so ähnlich habe ich es bereits umgesetzt.

    Ich komme da nicht weiter: