Async, Await

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.

    ich probier grad mit Async + Await, aber es zeigt keine Wirkung:

    VB.NET-Quellcode

    1. Private Async Sub btMoveMe_Click(sender As Object, e As EventArgs) Handles btMoveMe.Click
    2. btCancel.Visible = True
    3. ProgressBar1.Visible = True
    4. Dim pt = btMoveMe.Location
    5. Await MoveButton(pt, 100, 1)
    6. btMoveMe.Location = pt
    7. btCancel.Visible = False
    8. ProgressBar1.Visible = False
    9. End Sub
    10. Private Function MoveButton(pt As Point, count As Integer, stp As Integer) As Task
    11. For i = 0 To count - 1
    12. pt.Offset(stp, stp)
    13. 'Me.BeginInvoke(Sub() btMoveMe.Location = pt)
    14. Threading.Thread.Sleep(20)
    15. Next
    16. End Function
    Also das Form blockiert für 2 Sekunden - sonst nix
    Probier mal deine Funktion auch als Async zu markieren. msdn.microsoft.com/de-de/library/hh191564.aspx

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Await Move(Button2)
    3. End Sub
    4. Private Async Function Move(ByVal bt As Button) As Task
    5. For i As Integer = 0 To 10
    6. bt.Location = New Point(bt.Location.X + 10, bt.Location.Y + 10)
    7. Threading.Thread.Sleep(20)
    8. Next
    9. End Function

    Das klappt bei mir so.
    Edit: Sorry, Schwachsinn :)
    sieht so aus, aber nur scheinbar. Weil das Gui bleibt dabei blockiert, solange die Animation läuft.
    Guck - mit dieser Abwandlung wirds deutlicher:

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim pt = Button2.Location
    3. Await Move2(Button2)
    4. Button2.Location = pt
    5. End Sub
    6. Private Async Function Move2(ByVal bt As Button) As Task
    7. For i As Integer = 0 To 200
    8. bt.Location = New Point(bt.Location.X + 1, bt.Location.Y + 1)
    9. Threading.Thread.Sleep(20)
    10. Next
    11. End Function
    Währenddessen kann man das Form nicht verschieben.
    Die Move2 methode macht auch nix asynchrones. Dafür müsste der inhalt z.b.als task ausgeführt werden und dieser zurückgegeben werden.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    @ErfinderDesRades
    Das ganze ist iwie komisch.
    Ich hab mal Deinen Code etwas modifiziert. 3 Label, 1 Timer.

    VB.NET-Quellcode

    1. Imports System.Threading.Tasks
    2. Public Class Form1
    3. Private value As Long = 0
    4. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    5. Timer1.Interval = 20
    6. value = 0
    7. Timer1.Start()
    8. For i = 1 To 10000
    9. Label1.Text = i.ToString
    10. Label1.Refresh()
    11. If i = 5000 Then
    12. Try
    13. Await UseLabel2()
    14. Catch ex As Exception
    15. End Try
    16. End If
    17. Next
    18. 'Timer1.Stop()
    19. End Sub
    20. Private Function UseLabel2() As Task
    21. For i = 0 To 5000
    22. Label2.Text = i.ToString
    23. Label2.Refresh()
    24. Next
    25. Return New Task(Nothing)
    26. End Function
    27. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    28. Label3.Text = value.ToString
    29. value += 1
    30. End Sub
    31. End Class
    Dies hier ist noch blöder, die Task wird nicht ausgeführt:

    VB.NET-Quellcode

    1. Private Function UseLabel2() As Task
    2. Return New Task(Sub()
    3. For i = 0 To 5000
    4. Label2.Text = i.ToString
    5. Label2.Refresh()
    6. Next
    7. End Sub)
    8. End Function

    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!

    thefiloe schrieb:

    Die Move2 methode macht auch nix asynchrones. Dafür müsste der inhalt z.b.als task ausgeführt werden und dieser zurückgegeben werden.
    meinst du so?

    VB.NET-Quellcode

    1. Private Async Function Move2(ByVal bt As Button) As Task
    2. Return New Task(Sub()
    3. For i As Integer = 0 To 200
    4. bt.Location = New Point(bt.Location.X + 1, bt.Location.Y + 1)
    5. Threading.Thread.Sleep(20)
    6. Next
    7. End Sub)
    8. End Function
    Darauf CompilerFehler:

    Quellcode

    1. 'Return'-Anweisungen in dieser Async-Methode können keinen Wert zurückgeben, da der Rückgabetyp der Funktion 'Task' ist. Ziehen Sie in Betracht, den Rückgabetyp der Funktion in 'Task(Of T)' zu ändern.


    Wenn ich solch in Betracht ziehe, komme ich zu

    VB.NET-Quellcode

    1. Private Async Function Move3(ByVal bt As Button) As Task(Of Integer)
    2. Return New Task(Of Integer)(Function()
    3. For i As Integer = 0 To 200
    4. bt.Location = New Point(bt.Location.X + 1, bt.Location.Y + 1)
    5. Threading.Thread.Sleep(20)
    6. Next
    7. Return 9
    8. End Function)
    9. End Function
    mit dem CompilerFehler

    Quellcode

    1. Da es sich um eine asynchrone Methode handelt, muss der Rückgabeausdruck vom Typ 'Integer' anstelle von 'Task(Of Integer)' sein.


    Ich kann auch die Async-Kennzeichnung wegmachen, dann kompiliert immerhin:

    VB.NET-Quellcode

    1. Private Function Move2(ByVal bt As Button) As Task
    2. Return New Task(Sub()
    3. For i As Integer = 0 To 200
    4. bt.Location = New Point(bt.Location.X + 1, bt.Location.Y + 1)
    5. Threading.Thread.Sleep(20)
    6. Next
    7. End Sub)
    8. End Function
    Aber leider tut sich da zur Laufzeit garnix (ich hätte ja zumindest einen Laufzeitfehler erwartet)

    @Artentus: Ich hab keinen Plan mehr. Ich möchte mit Async einen Button übers Form laufen lassen, ohne CrossThread-Exception und ohne dass das Form einfriert.
    Ist das nicht zu schaffen?
    MoveButton sollte ungefähr so aussehen:

    VB.NET-Quellcode

    1. Private Async Sub MoveButton(pt As Point, count As Integer, stp As Integer)
    2. Await Task.Run(Sub()
    3. For i = 0 To count - 1
    4. pt.Offset(stp, stp)
    5. 'Me.BeginInvoke(Sub() btMoveMe.Location = pt)
    6. Threading.Thread.Sleep(20)
    7. Next
    8. End Sub)
    9. End Sub
    Jo, man braucht also 2 Methoden
    1. die async-Methode, die komisch ist, nämlich beim Await-Aufruf gewissermassen verfrüht returnt
    2. eine Methode, die einen (bereits gestarteten) Task returnt, in dem die eigliche Arbeitsmethode läuft.
      bessere Alternative: normale Arbeitsmethode schreiben, und eine anonyme Methode, die sie aufruft, an Task.Run übergeben.

    VB.NET-Quellcode

    1. Private Async Sub btMoveMe_Click(sender As Object, e As EventArgs) Handles btMoveMe.Click
    2. btCancel.Visible = True
    3. ProgressBar1.Visible = True
    4. ProgressBar1.Maximum = 100
    5. Dim pt = btMoveMe.Location
    6. 'Dim duration = Await GetMoveControlTask(btMoveMe, 100, 1) ' ausführenden Task holen
    7. 'besser: ausführenden Task selbst bilden
    8. Dim duration = Await Task.Run(Function() MoveControl(btMoveMe, 100, 1))
    9. Msg(duration)
    10. btMoveMe.Location = pt
    11. btCancel.Visible = False
    12. ProgressBar1.Visible = False
    13. End Sub
    14. Private Function GetMoveControlTask(ctl As Control, count As Integer, stp As Integer) As Task(Of Long)
    15. Dim pt = ctl.Location
    16. Return Task.Run(Function()
    17. Dim sw = Stopwatch.StartNew
    18. For i As Integer = 0 To count - 1
    19. pt.Offset(stp, stp)
    20. Me.BeginInvoke(Sub()
    21. ctl.Location = pt
    22. ProgressBar1.Increment(1)
    23. End Sub)
    24. Threading.Thread.Sleep(20)
    25. Next
    26. Return sw.ElapsedMilliseconds
    27. End Function)
    28. End Function
    29. Private Function MoveControl(ctl As Control, count As Integer, stp As Integer) As Long
    30. Dim sw = Stopwatch.StartNew
    31. Dim pt = ctl.Location
    32. For i As Integer = 0 To count - 1
    33. pt.Offset(stp, stp)
    34. Me.BeginInvoke(Sub()
    35. ctl.Location = pt
    36. ProgressBar1.Increment(1)
    37. End Sub)
    38. Threading.Thread.Sleep(20)
    39. Next
    40. Return sw.ElapsedMilliseconds
    41. End Function

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @Artentus @ErfinderDesRades
    Danke, nun hab ich meinen Ansatz auch auf die Reihe bekommen:

    VB.NET-Quellcode

    1. Imports System.Threading.Tasks
    2. Imports System.Threading.Thread
    3. Public Class Form1
    4. Private value As Long = 0
    5. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    6. Me.Timer1.Interval = 20
    7. Me.value = 0
    8. Me.Timer1.Start()
    9. Me.Button1.Location = New Point(16, 12)
    10. Await Task.Run(Sub() Me.MoveButton(Button1.Location, 200, 1))
    11. End Sub
    12. Private Async Sub MoveButton(pt As Point, count As Integer, stp As Integer)
    13. Await Task.Run(Sub()
    14. For i = 0 To count - 1
    15. pt.Offset(stp, stp)
    16. Me.BeginInvoke(Sub() Button1.Location = pt)
    17. Sleep(20)
    18. Next
    19. Me.Timer1.Stop()
    20. End Sub)
    21. End Sub
    22. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    23. Me.BeginInvoke(Sub()
    24. Me.Label1.Text = Me.value.ToString
    25. Me.value += 1
    26. End Sub)
    27. End Sub
    28. End Class
    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!
    Ich hab mir das jetzt nicht alles durchgelesen, aber probiert statt dem

    VB.NET-Quellcode

    1. Threading.Thread.Sleep
    mal

    VB.NET-Quellcode

    1. Await Task.Delay()


    Getestet und klappt, ist nicht das Gleich wie ihr wolltet, aber ist ja bestimmt kein Problem das umzuschreiben:

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Await Move()
    3. End Sub
    4. Private Async Function Move() As Task
    5. For i As Integer = 0 To 10
    6. Button1.Top += 5
    7. Await Task.Delay(1000)
    8. Next
    9. End Function

    Polling is trolling!

    Achtung: Ich habe die komische Angewohnheit, simple Dinge zu verkomplizieren..