David L. Hansen
asked on
Async with multiple UI objects
So I've been playing with Async and have had some success in making an asynchronous app. My practice code implements this:
This however, only allows the UI to receive focus when one other operation is underway (useful, but too limited for my use). I need to be able to have the UI receive focus while two other operations are underway. And it would be nice if these other operations could each influence the UI (form).
I've tried a couple other Async methods but when I do, the first and second operations always occur synchronously.
Can someone provide a simple example where Asyc kicks off multiple operations during runtime, and where the user still has control of the UI?
Await Task.Run(Sub()
LongOperation()
End Sub)
This however, only allows the UI to receive focus when one other operation is underway (useful, but too limited for my use). I need to be able to have the UI receive focus while two other operations are underway. And it would be nice if these other operations could each influence the UI (form).
I've tried a couple other Async methods but when I do, the first and second operations always occur synchronously.
Can someone provide a simple example where Asyc kicks off multiple operations during runtime, and where the user still has control of the UI?
ASKER
Mike,
I've taken your code and tried to run it as strait C# and also as converted VB. I think it's close but errors still exist. I've tried to find work-arounds but to no avail.
Here's the converted VB and its error message:
Did your C# code compile?
I've taken your code and tried to run it as strait C# and also as converted VB. I think it's close but errors still exist. I've tried to find work-arounds but to no avail.
Here's the converted VB and its error message:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim tasks As List(Of Task) = Enumerable.Range(1, 5).[Select](Function(i) Task.Run(Function() Threading.Thread.Sleep(i * 250 + 50))).ToList()
Await DoTheAsyncWork(tasks, AddressOf WriteResult)
Console.WriteLine("I'm not waiting for them ...")
End Sub
The sleep command won't compile, showing an "Expression does not produce a value" error. Did your C# code compile?
Change Function to Sub in your lambda.
i.e.
i.e.
...Task.Run(Sub() Threading.Thread...
ASKER
So it compiles now and runs, although it behaves synchronously. One through 10 (I changed it to 10) report one after the other, then the "I'm not waiting for them.." message is displayed.
Here is the code:
thx in advance.
Here is the code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim tasks As List(Of Task) = Enumerable.Range(1, 10).[Select](Function(i) Task.Run(Sub() Threading.Thread.Sleep(i * 250 + 50))).ToList()
Await DoTheAsyncWork(tasks, AddressOf WriteResult)
'Console.WriteLine("I'm not waiting for them ...")
Me.Label1.Text = "I'm not waiting for them ..."
Me.Label1.Refresh()
End Sub
Public Sub WriteResult(Result As String)
Console.WriteLine(Result)
End Sub
Public Async Function DoTheAsyncWork(tasks As List(Of Task), WriteResult As Action(Of String)) As Task
While tasks.Count() > 0
Dim FirstFinished As Task = Await Task.WhenAny(tasks.ToArray())
tasks.Remove(FirstFinished)
'WriteResult("Wait ended because task {FirstFinished.Id} completed.")
Me.Label2.Text = "Wait ended because task" & FirstFinished.Id.ToString & " completed."
Me.Label2.Refresh()
End While
End Function
End Class
thx in advance.
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
@MikeToole
You should really be using a thread-safe collection to store your tasks, since you are modifying that collection while threads are running.
You should really be using a thread-safe collection to store your tasks, since you are modifying that collection while threads are running.
@käµfm³d
My answer was aimed at the basic question.
Thread-safety is an extra - very important - consideration
Mike
My answer was aimed at the basic question.
Thread-safety is an extra - very important - consideration
Mike
ASKER
Can I impose on your kindness a bit longer (both of you)? I'm seeing some of what's going on here but not all. Even setting aside thread-safe practices, there are still a point of confusion.
The working code now has a warning from the compiler and I'm not sure why. Someone else already put the following question to some other experts which expresses my confusion:
The working code now has a warning from the compiler and I'm not sure why. Someone else already put the following question to some other experts which expresses my confusion:
The whole point of Async is that it's asynchronous. I don't want it to block, because I want to get back to the MainWorkOfApplicationIDontOne of the experts suggested that the warning (explained in the quote above) exists because most of the time we should await the tasks to finish before proceeding. Doesn't that defeat the purpose?WantBlocke d ASAP and let GetNameAsync do its thing in the background. However, calling it this way gives me a compiler warning on the GetNameAsync line:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
I'm perfectly aware that "execution of the current method continues before the call is completed". That's the point of asynchronous code, right?
SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
I guess that makes sense..we should at least track when the async work finishes.
So if I use a task variable to hold the resulting task returned from the Async function, the error message goes away. And I remade my app to track the task's status (ie. RanToCompletion, Faulted, WaitingForActivation, etc.).
This helps a lot. Thank you!
So if I use a task variable to hold the resulting task returned from the Async function, the error message goes away. And I remade my app to track the task's status (ie. RanToCompletion, Faulted, WaitingForActivation, etc.).
This helps a lot. Thank you!
Open in new window