I have a method that sends request to my server every second.
public async Task StartRequestProcess(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCanecllationRequested)
{
var result = await GetDataFromServerAsync();
await Task.Delay(1000, stoppingToken);
}
}
But my GetDataFromServerAsync() method takes 10 or 15 seconds sometimes.
What does in this time (10 or 15 seconds)?
Will process wait until complete long requests? Or will new requests send every second without wait?
I have a method that sends a request to my server every second.
No, you do not. Please do not open questions with false statements; it makes them hard to answer!
Your workflow is:
Request data
Wait for the data to arrive -- that's what asynchronously wait means. await is asynchronously wait.
Once the data has arrived, pause for a second, again, asynchronously
Repeat.
That is NOT the workflow "send a request every second". That is the workflow "send a request one second after the last request succeeded".
What does in this time (10 or 15 seconds)?
Asynchronously waits. You said to asynchronously wait until the data was available, and that's what it does. During the asynchronous wait other tasks can be scheduled to execute on the thread.
Will the workflow wait until the long request is completed?
Yes. It will wait asynchronously. Again, that's what await means. It means asynchronously wait.
Will new requests send every second without wait?
No. You said to wait until the data was received and then pause for one second, so that's what happens.
The whole idea of TAP (task Async pattern) is that a single thread can service lots of things "simultaneously" because it can go back to what it was doing before, any time that an await is in progress. This is why async marking on methods tends to be on every method right the way down in a hierarchy from the first point that the code you write (your controller Get method for example) through every method you call, right the way to where you need to wait something like db or network IO.
Encountering await is a bit like throwing an uncaught exception- control flow goes right the way back up the entire stack of methods that is your code, and out of the top, back to whatever was going on before, outside of your code. The difference between a thrown exception and an awaiting state machine is that when the task being awaited is done, the thread that went off to do other things will come back to where the await is and continue on from there
What it was doing before is highly contextual - in your case it's probably "waiting for a TCP client to connect and send some data"
Now, in your your code the thread goes back to what it was doing before- you say it takes 15 seconds so the thread will busy itself with other things for 15 seconds, then it will come back and wait for your 1000ms task to complete, then it will loop round and issue another request. In practice what this means is that every 16 seconds your code will make a request; not the request every second that you were hoping for. Use a timer
When you call await GetDataFromServerAsync(), execution of your method will resume once the asynchronous operation finishes, e.g., after 10 to 15 seconds. Only then will you wait asynchronously for another second.
Related
I tried reading many articles and questions in stackoverflow regarding the real use of async/await, so basically asynchronous method calls but somehow I am still not able to decode of how does it provide parallelism and non blocking behavior. I referred few posts like these
Is it OK to use async/await almost everywhere?
https://news.ycombinator.com/item?id=19010989
Benefits of using async and await keywords
So if I write a piece of code like this
var user = await GetUserFromDBAsync();
var destination = await GetDestinationFromDBAsync();
var address = await GetAddressFromDBAsync();
Even though all the three methods are asynchronous but still the code will not go to the second line to get destination from database until it fully gets the user from the database.
So where is the parallelism and non blocking behavior of asyn/await here. It still waits to complete the first operation before executing the next line.
Or my total understanding is wrong about asyn?
EDIT
Any example would really help!
The point of async/await is not that methods are executed more quickly. Rather, it's about what a thread is doing while those methods are waiting for a response from a database, the file system, an HTTP request, or some other I/O.
Without asynchronous execution the thread just waits. It is, in a sense, wasted, because during that time it is doing nothing. We don't have an unlimited supply of threads, so having threads sit and wait is wasteful.
Async/await simply allows threads to do other things. Instead of waiting, the thread can serve some other request. And then, when the database query is finished or the HTTP request receives a response, the next available thread picks up execution of that code.
So yes, the individual lines in your example still execute in sequence. They just execute more efficiently. If your application is receiving many requests, it can process those requests sooner because more threads are available to do work instead of blocking, just waiting for a response from some I/O operation.
I highly recommend this blog post: There Is No Thread. There is some confusion that async/await is about executing something on another thread. It is not about that at all. It's about ensuring that no thread is sitting and waiting when it could be doing something else.
You can execute them in parallel/concurrently and still await them in non-blocking manner withTask.WhenAll. You don't have to await each single async method call individually.
So you have the performance gain and at the same time a responsive UI:
//create 3 "cold" tasks, that are not yet running
var userTask = GetUserFromDBAsync();
var destinationTask = GetDestinationFromDBAsync();
var addressTask = GetAddressFromDBAsync();
//start running and awaiting all of them at (almost) the same time
await Task.WhenAll(userTask, destinationTask, adressTask);
//get the cached results
var user = userTask.Result;
var destination = destinationTask.Result;
var address = addressTask.Result;
I need some help in choosing the right tool. I'm replacing the hardware controller that controls some pumps with a raspberry pi and writing code for it in c# .netcore. The pumps should run in a specific sequence and for a specified duration. With all the possible ways to accomplish this, I'm looking for the cleanest and interesting one.
The pumps should do the following:
Turn on pump 1
wait 15 seconds
turn on pump 2
wait 10 minutes
turn on pump 3
let pump 3 run for 20 minutes
turn off pump 3
wait 10 minutes
turn off pump 2
wait 15 seconds
turn off pump 1
I looked into timers, threads, tasks, state machine but I have a hard time picking the right tool for this job. At all times, I also need to be able to stop immediately all pumps.
Thanks for your help.
I'd probably go with tasks.
public async Task Execute()
{
await TurnOnPump1();
await Task.Delay(TimeSpan.FromSeconds(15));
await TurnOnPump2();
await Task.Delay(TimeSpan.FromMinutes(10));
await TurnOnPump3();
//And so on..
}
To expand on the great answer from Magnus, here's how you could implement cancellation so you could stop executing the method (stop starting new pumps) if you decide to stop all of them.
I posted this answer because OP specifically said that they need to be able to stop the pumps at all times, so Magnus' answer wouldn't quite work in certain scenarios.
At all times, I also need to be able to stop immediately all pumps.
public async Task StartAll(CancellationToken ct)
{
await TurnOnPump1(); // no ct here because these methods should take little to no time to execute
await Task.Delay(TimeSpan.FromSeconds(15), ct);
await TurnOnPump2();
await Task.Delay(TimeSpan.FromMinutes(10), ct);
await TurnOnPump3();
//And so on..
}
public asnyc Task StopAll()
{
// Your_CancellationTokenSource should be defined somewhere else
Your_CancellationTokenSource.Cancel(); // this line makes Task.Delay throw a TaskCanceledException
await StopPump1();
await StopPump2();
await StopPump3();
// ..
}
public async Task HowToCallStart()
{
try
{
// Your_CancellationTokenSource should be defined somewhere else
await StartAll(Your_CancellationTokenSource.Token);
}
catch (TaskCanceledException)
{
// Starting was canceled
}
}
This way, StopAll can be called anytime during the starting and you don't get any issues.
A few things to mention:
Your_CancellationTokenSource should of course be some variable outside of these methods so it can be shared. It needs to be of type CancellationTokenSource.
As you can see by the comment (both in code and below answer), I assumed that starting a pump would be very fast and take very little to no time. That is the reason I did not pass in my CancellationToken.
If turning on the pumps takes some time, consider using CancellationToken inside the TurnOnPumpX methods as well to abort if the operation was canceled. If you do so, you can simply pass in ct to those methods as well.
You should add some code in the catch for when the operation is canceled. At least print out a debug message if the end-user doesn't need to see it.
I am currently developing a service which basically waits for data on a stream. The service can be cancelled at any time, but in most cases it runs for a long period (days). I like to switch my asynchronous design from using BackgroundWorker and a loop which checks the current cancellation state of the BackgroundWorker and the availability of some data on stream to a much better design using Tasks (as the BackgroundWorker is not the best choice for long running threads, as it takes a ThreadPool-Thread).
My current loop / routine looks basically like this:
while(!cancelled) {
CheckIfDataAvailable(); // This check is non-blocking
Thread.Sleep(500);
}
What I basically want to do now is get rid of the Thread.Sleep() call, but in the same time the thread should be cancelable in a fair amount of time while also listening if any data is available on a stream (and this operation might block the stream or hinders the check of the cancelation state in some other way).
I know how to cancel a Task using a CancellationToken but I am not aware of any method combining the cancel-check and the data availability check in a really clean manner (e.g. not using Thread.Sleep()).
Use Task.Delay, e.g., as follows:
async Task BackgroundWord(CancellationToken token)
{
CheckIfDataAvailable();
await Task.Delay(TimeSpan.FromSeconds(x), token);
}
If your CheckIfDataAvailable method returns a Task (that is completed when data is available), you can combine the two as follows:
await Task.WhenAny(CheckIfDataAvailable(), Task.Delay(-1, token));
Task.Delay(-1) will wait forever, so it will only transfer to the completed state if the cancellation token is cancelled. Thus Task.WhenAny will wait for either data to become available, or the token to be cancelled.
I have a couple of hundred devices and I need to check their status every 5 seconds.
The API I'm using contains a blocking function that calls a dll and returns a status of a single device
string status = ReadStatus(int deviceID); // waits here until the status is returned
The above function usually returns the status in a couple of ms, but there will be situations where I might not get the status back for a second or more! Or even worse, one device might not respond at all.
I therefore need to introduce a form of asynchronicity to make sure that one device that doesn't respond doesn't impend all the others being monitored.
My current approach is as following
// triggers every 5 sec
public MonitorDevices_ElapsedInterval(object sender, ElapsedEventArgs elapsedEventArgs)
{
foreach (var device in lstDevices) // several hundred devices in the list
{
var task = device.ReadStatusAsync(device.ID, cts.Token);
tasks.Add(task);
}
// await all tasks finished, or timeout after 4900ms
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(4900, cts.Token));
cts.Cancel();
var devicesThatResponded = tasks.Where(t => t.Status == TaskStatus.RanToCompletion)
.Select(t => t.GetAwaiter().GetResult())
.ToList();
}
And below in the Device class
public async Task ReadStatusAsync(int deviceID, CancellationToken tk)
{
await Task.Delay(50, tk);
// calls the dll to return the status. Blocks until the status is return
Status = ReadStatus(deviceID);
}
I'm having several problems with my code
the foreach loops fires a couple of hundred tasks simultaneously, with the callback from the Task.Delay being served by a thread from the thread pool, each task taking a couple of ms.
I see this as a big potential bottleneck. Are there any better approaches?
This might be similar to what Stephen Cleary commented here, but he didn't provide an alternative What it costs to use Task.Delay()?
In case ReadStatus fails to return, I'm trying to use a cancellation token to cancel the thread that sits there waiting for the response... This doesn't seem to work.
await Task.Delay(50, tk)
Thread.Sleep(100000) // simulate the device not responding
I still have about 20 Worker Threads alive (even though I was expecting cts.Cancel() to kill them.
the foreach loops fires a couple of hundred tasks simultaneously
Since ReadStatus is synchronous (I'm assuming you can't change this), and since each one needs to be independent because they can block the calling thread, then you have to have hundreds of tasks. That's already the most efficient way.
Are there any better approaches?
If each device should be read every 5 seconds, then each device having its own timer would probably be better. After a few cycles, they should "even out".
await Task.Delay(50, tk);
I do not recommend using Task.Delay to "trampoline" non-async code. If you wish to run code on the thread pool, just wrap it in a Task.Run:
foreach (var device in lstDevices) // several hundred devices in the list
{
var task = Task.Run(() => device.ReadStatus(device.ID, cts.Token));
tasks.Add(task);
}
I'm trying to use a cancellation token to cancel the thread that sit there waiting for the response... This doesn't seem to work.
Cancellation tokens do not kill threads. If ReadStatus observes its cancellation token, then it should cancel; if not, then there isn't much you can do about it.
Thread pool threads should not be terminated; this reduces thread churn when the timer next fires.
As you can see in this Microsoft example page of a cancellation token, the doWork method is checking for cancellation on each loop. So, the loop has to start again to cancel out. In your case, when you simulate a long task, it never checks for cancellation at all when it's running.
From How do I cancel non-cancelable async operations?, it's saying at the end : "So, can you cancel non-cancelable operations? No. Can you cancel waits on non-cancelable operations? Sureā¦ just be very careful when you do.". So it answers that we can't cancel it out.
What I would suggest is to use threads with a ThreadPool, you take the starting time of each one and you have an higher priority thread that looks if others bypass their maximum allowed time. If so, Thread.Interrupt().
I am new in Windows Phone development and I am trying to create a windows phone app using C#
Thread t = new Thread(doaheavywork);
t.Start();
if (!t.Join(1000)) // give the operation 1s to complete
{
t.Abort();
}
I cannot alter the doaheavywork function.
I just need the result to be omputed within 1 or 2 seconds, since sometimes it may run for very long time.
I have read using abort is the wrong way.
I am using the above in a PhotoChooserTask complete function. First run executes fine. That is, when I click the button to select a photo, the doaheavywork function doesn't exceed 1 sec. But if I try for the second time, the PhotoChooserTask just throws an exception and stops.
Is it because I aborted the process in 1st run? Or anything else? Is there any other way to do it?
.Abort() causes the thread to be destroyed completely. If you are generating a new thread each time like in your example, then it will work. However if you are using the same t object, then you need to create a new thread object, you can't run .Start() on an aborted thread.
However the fact you are aborting a thread is a concern. What happens with the application when it does take more than 2 seconds. Should you be showing the user, please wait, its taking longer than expected. Doing that in the if block is where to do it. .Join() won't stop the thread even if it doesn't manage to join.
Edit
You have 2 options you might want to consider in rewriting this section:
BackgroundWorker - http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx
Thread Task - http://msdn.microsoft.com/en-us/library/windowsphone/develop/cc221403(v=vs.105).aspx
Tasks seem to be the appropriate solution in your scenario.
One approach maybe be to consider using a Task and having a CancellationToken passed in to it from a CancellationTokenSource instantiated against a specific timespan - 2 seconds. That way when the the time specified has elapsed, the CancellationToken, passed to the Task, will be signaled and then appropriate action can be taken.