For years I create delays in my software using, for example:
Wait(10000)
Sub Wait(milliseconds)
<here I get the current time>
Do
<here I loop until the current time passed in seconds and then exit this loop>
Application.DoEvents()
Loop
End Sub
The problem is, this uses a lot of CPU. I tried Thread.Sleep(1000), but this FREEZES my application while it's performing!
I tried using a Timer, but I STILL need a loop that doesn't freeze yet acts like Application.DoEvents(). It seems impossible.
My goal is to do this:
label1.text = "ok about to start"
Wait(5000)
' the following line CAN NOT run until after 5 seconds.
label1.text = "DONE"
How to execute code after a delay.
There are different methods to execute code after a delay or execute it asynchronously, after a delay or not. Here, I'm considering a Timer and simple implementations of the Async/Await pattern.
A loop that calls
Application.DoEvent()should be avoided in any case.► Using a Timer to delay the execution of a single instruction or the code in one or more methods:
You cannot await for a Timer, but you can use a method that creates a Timer and executes an Action when the Timer raises its event, signaling that the Interval specified has elapsed.
The method that follows accept as arguments a
delayvalue and an Action delegate.The Delay is used to set the Timers' Interval, the Action represent the code that will be executed when the Timer Ticks (I'm using a System.Windows.Forms.Timer here, since you seem to refer to a WinForms application).
We can call this method when we need to execute code after a delay.
The Action can be a simple instruction: in this case, the Text of
label1will be set to "Done" after 5 seconds, while the UI Thread continues its operations:The Action can also be a method:
Of course the
SetControlText()method can execute more complex code and, optionally, set a Timer itself, callingWait().► Using the Async/Await pattern.
In simple terms, adding the Async modifier to a method, allows to use the Await operator to wait for an asynchronous procedure to terminate before the code that follows is executed, while the current Thread is free to continue its processing.
▬ Note that the
Asyncmodifier is always applied to aFunction()that returns aTaskor aTask(Of something)(something can be any value/reference a method can return).It's only applied to a
Sub()when theSub(void) method represents anEvent Handler. This is very important to remember and apply without exceptions (unless you're quite aware of the implications). ▬Read the Docs about this (in the previous link) and these:
Async and Await
Don't Block on Async Code
A simple
Asyncmethod can be used to delay the execution of an action:This is similar to the Timer functions and acts in a similar way. The difference is that you can
Awaitthis method to both execute the code it runs asynchronously and to wait for its completion to run other code after the method returns. The calling Thread (the UI Thread, here), will continue its operations while theWait()method is awaited.Assume that, in a
Button.Clickhandler, we want to execute an Action (a method that doesn't return a value) or a Function (a method that returns a value) and the code that follows should execute only after this Action or Function returns:Here, we instruct to wait for 5 seconds, then set the Text of a Label to a value, wait other 5 seconds, doing nothing, then execute the code that follows
If we don't need to perform an Action, we can simply use Task.Delay():
We can also use Async/Await to wait for the completion of a Task run in a ThreadPool Thread, calling Task.Run() to execute code in a Lambda expression:
(just an example, we shouldn't use a ThreadPool Thread for such a simple task)
See also the Task.ContinueWith() method: