locked
Async / await freezing main page RRS feed

  • Question

  • I'm trying to have 'ClassSqlListenerAsync.Listen' to run without hanging the main screen. but I can't get it to run without hanging mainpage. I tried to seperate it from the main thread as much as I could for testing(the reason FriendGameID and FriendPlayerID are just sent as straight strings "a" and "1" from the button)

    Can anyone tell me what I'm doing wrong? My guess is maybe the Await but I'm not sure How to change it

    Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
          
            Await ClassSqlListeterAsync.Listen("a", "2")
            
        End Sub
    
    Imports MySql.Data.MySqlClient
    Public Class ClassSqlListeterAsync
    
        Public Shared Async Function Listen(ByVal FriendGameID, ByVal FriendPlayerID) As Task(Of String())
    
            Dim Emy As String()
            Do
                Using con As New MySqlConnection(ClassMySqlConnect.SQLConnect)
                    con.Open()
                    Using cmd As MySqlCommand = con.CreateCommand()
                        Dim Enemy = New String(9) {}
    
                        cmd.CommandText = "select `GameID`,`PlayerID`,`TurnID`,`CharacterID`,`CP`,`Stamina`,`Recovery`,`AttackType`,`AttackValue`,`AName` FROM `Toons` Where `GameID` = " & "'" & FriendGameID & "' and not `PlayerID` = " & "'" & FriendPlayerID & "'"
    
                        Using reader As MySqlDataReader = Await Task.FromResult(Of Object)(cmd.ExecuteReader())
                            If Not reader.Read() Then
                                Enemy(0) = "NoData"
                                Enemy(1) = "0" '"PlayerID"
                                Enemy(2) = "0" '"TurnID"
                                Enemy(3) = "0" '"CharacterID"
                                Enemy(4) = "0" '"CP"
                                Enemy(5) = "0" '"STamina"
                                Enemy(6) = "0" '"Recovery"
                                Enemy(7) = "0" '"AttackType"
                                Enemy(8) = "0" '"AttackValue"
                                Enemy(9) = "0" '"AName"
    
    
                            Else
                                Enemy(0) = reader.GetString(0) 'GameID
                                Enemy(1) = reader.GetString(1) 'PlayerID
                                If Enemy(1) = "" Then
                                    Enemy(1) = "0"
                                End If
                                Enemy(2) = reader.GetString(2) 'TurnID
                                Enemy(3) = reader.GetString(3) 'CharacterID
                                Enemy(4) = reader.GetString(4) 'CP
                                Enemy(5) = reader.GetString(5) 'Stamina
                                Enemy(6) = reader.GetString(6) 'Recovery
                                Enemy(7) = reader.GetString(7) 'AttackType
                                Enemy(8) = reader.GetString(8) 'AttackValue
                                Enemy(9) = reader.GetString(9) 'AName
    
                            End If
    
    
                            Emy = Enemy
    
                            reader.Close()
                        End Using
                    End Using
                End Using
    
            Loop While Emy(0) = "NoData"
            Return Emy
        End Function
    
    End Class

    Tuesday, May 6, 2014 3:59 PM

Answers

  • Just wanted to let you know that I found a solution to this issue. I simply used  await Task.Delay(3000) before the time consuming code. That allowed enough time for the Main ui to refresh itself before continuing. Works Great now
    • Marked as answer by PBPuddin Tuesday, May 13, 2014 9:16 PM
    Tuesday, May 13, 2014 9:16 PM

All replies

  • It looks like that's still busy-looping on the main thread. Break in the debugger and look to see which thread that is running on?

    You'll probably want to throw the database reference into a worker thread (e.g. with Task.Run )

    --Rob

    Wednesday, May 7, 2014 2:26 AM
    Moderator
  • ok, I tried to put the whole class on a seperate thread with task run like so

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
          
    
            Dim t As Task(Of String()) = Task(Of String()).Run(Async Function()
                        Dim player As String() = Await ClassSqlListenerAsync.Listen("a", "2")
    
                                                                   Return player
                                                               End Function)
    
            lblOutputField.Text = t.Result(4).ToString
            
            
        End Sub

    But it still Freezes the Main Page. Any Ideas?

    Wednesday, May 7, 2014 4:59 AM
  • I put some breakpoints in the code for each of the lines in my last code sample and I get the following in the output window:

    The thread 0x10a0 has exited with code 259 (0x103).
    The thread 0x1050 has exited with code 0 (0x0).
    The thread 0xccc has exited with code 0 (0x0).
    The thread 0x1984 has exited with code 0 (0x0).

    So I think it seems to be opening new threads. However I don't know how to tell what is running on which thread

    Wednesday, May 7, 2014 5:23 AM
  • I used the example from page Asynchronous Programming with Async and Await (C# and Visual Basic) and built the following calling method for the listener class (ClassSqlListeterAsync.Listen) Above. and came up with this code below. The Listen method works and when it finds a match it returns it correctly but when it doesn't find the match right away the main page just locks and none ot the changes to lblOutputField.text happen

    Private Async Sub StartListenerAsync()
    
            FriendGameID = "a"
            FriendPlayerID = "2"
            lblOutputField.Text = "Starting Search"
    
            ' ClassSqlListenerAsync.Listen returns a Task(Of String()). That means that when you await the 
            ' task you'll get a string Array (Current Players Move). 
            Dim t As Task(Of String()) = ClassSqlListenerAsync.Listen("a", "2")
    
    
            ' You can do work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork()
    
            ' The Await operator suspends StartListenerAsync. 
            '  - StartListenerAsync can't continue until getStringTask is complete. 
            '  - Meanwhile, control returns to the caller of StartListenerAsync. 
            '  - Control resumes here when getStringTask is complete.  
            '  - The Await operator then retrieves the string result from getStringTask. 
            Dim player As String() = Await t
    
            ' The return statement specifies an integer result. 
            ' Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    
    
            lblOutputField.Text = player(4).ToString
            lblCP.Text = "Hello"
        End Sub

    Private Sub DoIndependentWork()
            lblOutputField.Text = "Search Started"
        End Sub





    • Edited by PBPuddin Wednesday, May 7, 2014 5:43 PM forgot to select proper language
    Wednesday, May 7, 2014 5:27 PM
  •  I can't seem to see what I'm missing with this async/ await method. I've tried to do the following test and it locks up my main thread also. I am missing something vital here. after all the hours of reading up on thin the following code should run on it's own thread and not stop the main thread but it does. why? I beleive this is the same issue I'm having above.

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
                    loopstart()
        End Sub
    
        Private Async Sub loopstart()
            Await superlooper()
        End Sub
    
        Private Async Function superlooper() As Task
            Dim i As Integer = 1
            Do While i = 1
    
            Loop
    
            Await Task.Delay(10)
    
        End Function

    I believe this should create an endless loop on an async thread without stoping the main thread... right?

    Wednesday, May 7, 2014 5:41 PM
  • Not quite. This will loop on the UI thread and hang.The Await Task.Delay call won't ever be hit since the while loop will never exit.

    Awaiting does not itself do any threading. It is syntactic sugar to split the function into the part before the await and to a part which gets called when the awaited Task completes. The Task will generally set up an asynchronous call (on another thread, posted to a web service, etc.) and then return so the UI thread will continue going. When the Tasks' internal call (threadpool calculations complete, web service responds, etc.) it will call its completion handler and the code after the await runs.

    In your case the Task just loops forever without deferring anything asynchronously and giving the app a chance to respond.

    Calling your busy code in a ThreadPool (as I suggested previously) will let Task return control to the UI thread while the busy code is churning away.

    --Rob

    Wednesday, May 7, 2014 6:10 PM
    Moderator
  • ok Rob, (thanks for the help by the way)

    I did try to call the code with the task.run like you said(see my response above for actual code) but it still freezes. am I not calling task run correctly there

    Wednesday, May 7, 2014 6:19 PM
  • Just wanted to let you know that I found a solution to this issue. I simply used  await Task.Delay(3000) before the time consuming code. That allowed enough time for the Main ui to refresh itself before continuing. Works Great now
    • Marked as answer by PBPuddin Tuesday, May 13, 2014 9:16 PM
    Tuesday, May 13, 2014 9:16 PM