Task.Run() Delay, when first called - c#

I am running a Thread which get called in a static interval.
In this Thread I am running several Tasks (20-200).
All this works fine, but when the Thread gets called the first time, it takes like ~1 sec for one Tasks to start.
As soon as the while loop is in the second loop or when the Thread stops, and gets called a second time, the problem is gone.
public static async void UpdateThread()
{
while(!stop)
{
foreach (DSDevice device in DSDevices)
{
var task = Task.Run(() =>
{
// Delay is measured here
// Do Stuff
});
}
//No Delay
await Task.WhenAll(tasks);
Thread.Sleep(Sleeptime);
}
}

The Task.Run runs the code on the ThreadPool, and the ThreadPool creates initially a limited number of threads on demand. You can increase this limit with the SetMinThreads method:
ThreadPool.SetMinThreads(200, 200);
...but check out the documentation before doing so. Increasing this threshold is not something that you should do without thinking. Having too many ThreadPool threads defeats the purpose of having a pool in the first place. Think whether it's better to have a dedicated thread per device, for the whole life-time of the program.
As a side note, if I was in your shoes I would not parallelize the processing of the devices by creating tasks manually. I would use the Parallel.ForEach method, which exists for exactly this kind of job. As a bonus it allows to control the degree of parallelism, either to a specific number or to -1 for unlimited parallelism:
public static async Task MonitorDevicesPeriodicAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
Task delayTask = Task.Delay(MonitorDevicesPeriodMilliseconds);
await Task.Run(() =>
{
ParallelOptions options = new() { MaxDegreeOfParallelism = -1 };
Parallel.ForEach(DSDevices, options, device =>
{
// Do Stuff with device
});
});
await delayTask;
}
}
The Parallel.ForEach invokes also the delegate on the ThreadPool (by default), and it can saturate it as easily as the await Task.WhenAll(tasks) approach, so you might need to use the ThreadPool.SetMinThreads method as well.
Three more off topic suggestions: prefer async Task over async void. Async void is intended for event handler only. Also use a CancellationToken for stopping the while loop instead of a non-volatile bool stop field. In a multithreaded environment, it's not guaranteed that the mutation of the field from one thread will be visible from other threads. Alternatively declare the field as volatile. Finally use the Task.Delay instead of the Thread.Sleep, create the Task.Delay task at the start of the iteration and await it at the end, for a stable periodic invocation.

Related

Why do I get a warning when trying to run an async method on another thread?

I have an async method, which calls another async method, however, I want it run on a separate thread in parallel:
public async Task<Page> ServePage() {
Task.Run(() => DoThings(10)); // warning here
// ... other code
return new Page();
}
public async Task DoThings(int foo) {
// stuff
}
The warning states:
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.
That is, in fact, what I am trying to do. Why am I getting a compiler warning? Is the syntax of Task.Run incorrect?
TL;DR
The reason why you get the warning is because
Task.Run(() => DoThings(10)); // warning here
returns a Task, and since your ServePage method is marked as async, the compiler believes that you should await the result of the Task
Detail
You're mixing two very different paradigms, which coincidentally both involve Task, viz:
Task.Run(), which is generally useful for parallelizing CPU bound work by utilizing multiple cores which may be available
async / await, which is useful for waiting for I/O bound operations to complete, without blocking (wasting) a thread.
So for instance, if you wanted to do 3 x CPU bound operations concurrently, and since Task.Run returns a Task, what you could do is:
public Page ServePage() // If we are CPU bound, there's no point decorating this as async
{
var taskX = Task.Run(() => CalculateMeaningOfLife()); // Start taskX
var taskY = Task.Run(() => CalculateJonSkeetsIQ()); // Start taskY
var z = DoMoreHeavyLiftingOnCurrentThread();
Task.WaitAll(taskX, taskY); // Wait for X and Y - the Task equivalent of `Thread.Join`
// Return a final object comprising data from the work done on all three tasks
return new Page(taskX.Result, taskY.Result, z);
}
The above is likely to utilise up to three threads, which could do the CPU bound work concurrently if there are sufficient cores to do so. Note however that using multiple threads concurrently will reduce the scalability of your system, since fewer simultaneous pages can be served without context switching.
This is in contrast to async / await, which is generally used to free up threads while waiting for I/O bound calls to complete. Async is commonly used in Api and Web apps to increase scalability as the thread is released for other work while the IO bound work happens.
Assuming DoThings is indeed I/O bound, we can do something like:
public async Task<string> DoThings(int foo) {
var result = await SomeAsyncIo(foo);
return "done!";
}
Async work can also be done in parallel:
public async Task<Page> ServePage() {
var task1 = DoThings(123); // Kick off Task 1
var task2 = DoThings(234); // Kick off Task 2 in parallel with task 1
await Task.WhenAll(task1, task2); // Wait for both tasks to finish, while releasing this thread
return new Page(task1.Result, task2.Result); // Return a result with data from both tasks
}
If the I/O bound work takes a reasonable amount of time, there's a good chance there's a point during the await Task.WhenAll when ZERO threads are actually running - See Stephen Cleary's article.
There's a 3rd, but very dangerous option, which is fire and forget. Since method DoThings is already marked as async, it already returns a Task, so there's no need at all to use Task.Run at all. Fire and forget would look as follows:
public Page ServePage() // No async
{
#pragma warning disable 4014 // warning is suppresed by the Pragma
DoThings(10); // Kick off DoThings but don't wait for it to complete.
#pragma warning enable 4014
// ... other code
return new Page();
}
As per #JohnWu's comment, the 'fire and forget' approach is dangerous and usually indicates a design smell. More on this here and here
Edit
Re:
there is nuance to this that escapes me over and over, such as that calling an async method that returns Task from a synchronous method fires-and-forgets execution of the method. (That's the very last code sample.) Am I understanding that correctly?
It's a bit difficult to explain, but irrespective of whether called with, or without the await keyword, any synchronous code in an invoked async method before the first await will be executed on the caller's thread, unless we resort to hammers like Task.Run.
Perhaps this example might help the understanding (note that we're deliberately using synchronous Thread.Sleep and not await Task.Delay to simulate CPU bound work and introduce latency which can be observed)
public async Task<Page> ServePage()
{
// Launched from this same thread,
// returns after ~2 seconds (i.e. hits both sleeps)
// continuation printed.
await DoThings(10);
#pragma warning disable 4014
// Launched from this same thread,
// returns after ~1 second (i.e. hits first sleep only)
// continuation not yet printed
DoThings(10);
// Task likely to be scheduled on a second thread
// will return within few milliseconds (i.e. not blocked by any sleeps)
Task.Run(() => DoThings(10));
// Task likely to be scheduled on a second thread
// will return after 2 seconds, although caller's thread will be released during the await
// Generally a waste of a thread unless also doing CPU bound work on current thread, or unless we want to release the calling thread.
await Task.Run(() => DoThings());
// Redundant state machine, returns after 2 seconds
// see return Task vs async return await Task https://stackoverflow.com/questions/19098143
await Task.Run(async () => await DoThings());
}
public async Task<string> DoThings(int foo) {
Thread.Sleep(1000);
var result = await SomeAsyncIo(foo);
Trace.WriteLine("Continuation!");
Thread.Sleep(1000);
return "done!";
}
There's one other important point to note - in most cases, there are no guarantees that the continuation code AFTER an await will be executed on the same thread as that before the await. The continuation code is re-written by the compiler into a Task, and the continuation task will be scheduled on the thread pool.
This
Task.Run(() => DoThings(10));
will run your separate task "in parallel", meaning that another thread will run this task. The thread that entered this method will then continue execution of the next statement.
What you're doing here is allowed. That's why it's a warning. (I'm assuming that the rest of the method, not shown, returns a Page.)
The message is warning you that because the other task is executing on another thread, it could execute before, after, or at the same time as the other code in the method. This method no longer "knows" what the task is doing or when it's finished.
It's saying, in other words:
Don't assume that because this line of code appears before other lines of code in the method that it's going to execute before they do. If something needs to execute after this task finishes, await it before doing the next thing.
As an example:
public int DoSomething()
{
var x = 1;
Task.Run(() => x++);
return x;
}
What does this return? It depends. It could return 1 or 2. It may return either before or after x is incremented. If you care whether or not x has been incremented then this is bad. If your task does something that doesn't matter to the rest of the method and you don't care whether the task even finishes before or after the rest of the method, then this warning wouldn't matter to you. If you do care then it's important and you'd want to await the task.
All versions bellow are valid, warning free, and more or less equivalent:
public Task ServePage1()
{
return Task.Run(async () => await DoThings(10));
}
public async Task ServePage2()
{
await Task.Run(async () => await DoThings(10));
}
public Task ServePage3()
{
return Task.Run(() => DoThings(10));
}
public async Task ServePage4()
{
await Task.Run(() => DoThings(10));
}
In general you should not fire-and-forget tasks by ignoring the return value of Task.Run. If you do that the compiler will issue a warning, because it is rarely intentional.
When you call an async method that returns a Task, you can do two things:
Await the Task, which returns control to the caller immediately, and resumes when the Task completes (with or without a return value). This is also where you can trap any exceptions that might have happened when executing the Task.
Fire and Forget. This is when you start a Task and completely cut it loose - including the ability to trap exceptions. Most importantly, unless awaited, control execution will proceed beyond the call and can cause unintended state corruption issues.
You did #2 in your code. While technically allowed, because of the reasons cited above, the compiler warned you.
Question for you though - if you really just wanted to fire and forget, why did you need to create that explicit Task? You could just have called DoThings(10) directly, couldn't you? Unless I am missing something in the code that is not visible to me.
So - couldn't you have done just this?
public async Task<Page> ServePage() {
DoThings(10);
}

What's the difference between starting and awaiting a Task?

What's the difference between starting and awaiting? Code below taken from Stephen Cleary's blog (including comments)
public async Task DoOperationsConcurrentlyAsync()
{
Task[] tasks = new Task[3];
tasks[0] = DoOperation0Async();
tasks[1] = DoOperation1Async();
tasks[2] = DoOperation2Async();
// At this point, all three tasks are running at the same time.
// Now, we await them all.
await Task.WhenAll(tasks);
}
I thought that the tasks begin running when you await them ... but the comments in the code seem to imply otherwise.
Also, how can the tasks be running after I just attributed them to an array of type Task. Isn't that just an attribution, by nature not involving action?
A Task returns "hot" (i.e. already started). await asynchronously waits for the Task to complete.
In your example, where you actually do the await will affect whether the tasks are ran one after the other, or all of them at the same time:
await DoOperation0Async(); // start DoOperation0Async, wait for completion, then move on
await DoOperation1Async(); // start DoOperation1Async, wait for completion, then move on
await DoOperation2Async(); // start DoOperation2Async, wait for completion, then move on
As opposed to:
tasks[0] = DoOperation0Async(); // start DoOperation0Async, move on without waiting for completion
tasks[1] = DoOperation1Async(); // start DoOperation1Async, move on without waiting for completion
tasks[2] = DoOperation2Async(); // start DoOperation2Async, move on without waiting for completion
await Task.WhenAll(tasks); // wait for all of them to complete
Update
"doesn't await make an async operation... behave like sync, in this example (and not only)? Because we can't (!) run anything else in parallel with DoOperation0Async() in the first case. By comparison, in the 2nd case DoOperation0Async() and DoOperation1Async() run in parallel (e.g. concurrency,the main benefits of async?)"
This is a big subject and a question worth being asked as it's own thread on SO as it deviates from the original question of the difference between starting and awaiting tasks - therefore I'll keep this answer short, while referring you to other answers where appropriate.
No, awaiting an async operation does not make it behave like sync; what these keywords do is enabling developers to write asynchronous code that resembles a synchronous workflow (see this answer by Eric Lippert for more).
Calling await DoOperation0Async() will not block the thread executing this code flow, whereas a synchronous version of DoOperation0 (or something like DoOperation0Async.Result) will block the thread until the operation is complete.
Think about this in a web context. Let's say a request arrives in a server application. As part of producing a response to that request, you need to do a long-running operation (e.g. query an external API to get some value needed to produce your response). If the execution of this long-running operation was synchronous, the thread executing your request would block as it would have to wait for the long-running operation to complete. On the other hand, if the execution of this long-running operation was asynchronous, the request thread could be freed up so it could do other things (like service other requests) while the long-running operation was still running. Then, when the long-running operation would eventually complete, the request thread (or possibly another thread from the thread pool) could pick up from where it left off (as the long-running operation would be complete and it's result would now be available) and do whatever work was left to produce the response.
The server application example also addresses the second part of your question about the main benefits of async - async/await is all about freeing up threads.
Isn't that just an attribution, by nature not involving action?
By calling the async method you execute the code within. Usually down the chain one method will create a Task and return it either by using return or by awaiting.
Starting a Task
You can start a Task by using Task.Run(...). This schedules some work on the Task Thread Pool.
Awaiting a Task
To get a Task you usually call some (async) Method that returns a Task. An async method behaves like a regular method until you await (or use Task.Run() ). Note that if you await down a chain of methods and the "final" method only does a Thread.Sleep() or synchronous operation - then you will block the initial calling thread, because no method ever used the Task's Thread Pool.
You can do some actual asynchronous operation in many ways:
using Task.Run
using Task.Delay
using Task.Yield
call a library that offers asynchronous operations
These are the ones that come to my mind, there are probably more.
By example
Let's assume that Thread ID 1 is the main thread where you are calling MethodA() from. Thread IDs 5 and up are Threads to run Tasks on (System.Threading.Tasks provides a default Scheduler for that).
public async Task MethodA()
{
// Thread ID 1, 0s passed total
var a = MethodB(); // takes 1s
// Thread ID 1, 1s passed total
await Task.WhenAll(a); // takes 2s
// Thread ID 5, 3s passed total
// When the method returns, the SynchronizationContext
// can change the Thread - see below
}
public async Task MethodB()
{
// Thread ID 1, 0s passed total
Thread.Sleep(1000); // simulate blocking operation for 1s
// Thread ID 1, 1s passed total
// the await makes MethodB return a Task to MethodA
// this task is run on the Task ThreadPool
await Task.Delay(2000); // simulate async call for 2s
// Thread ID 2 (Task's pool Thread), 3s passed total
}
We can see that MethodA was blocked on the MethodB until we hit an await statement.
Await, SynchronizationContext, and Console Apps
You should be aware of one feature of Tasks. They make sure to invoke back to a SynchronizationContext if one is present (basically non-console apps). You can easily run into a deadlock when using .Result or .Wait() on a Task if the called code does not take measures. See https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
async/await as syntactic sugar
await basically just schedules following code to run after the call was completed. Let me illustrate the idea of what is happening behind the scenes.
This is the untransformed code using async/await. The Something method is awaited, so all following code (Bye) will be run after Something completed.
public async Task SomethingAsync()
{
Hello();
await Something();
Bye();
}
To explain this I add a utility class Worker that simply takes some action to run and then notify when done.
public class Worker
{
private Action _action;
public event DoneHandler Done;
// skipping defining DoneHandler delegate
// store the action
public Worker(Action action) => _action = action;
public void Run()
{
// execute the action
_action();
// notify so that following code is run
Done?.Invoke();
}
}
Now our transformed code, not using async/await
public Task SomethingAsync()
{
Hello(); // this remains untouched
// create the worker to run the "awaited" method
var worker = new Worker(() => Something());
// register the rest of our method
worker.Done += () => Bye();
// execute it
worker.Run();
// I left out the part where we return something
// or run the action on a threadpool to keep it simple
}
Here's the short answer:
To answer this you just need to understand what the async / await keywords do.
We know a single thread can only do one thing at a time and we also know that a single thread bounces all over the application to various method calls and events, ETC. This means that where the thread needs to go next is most likely scheduled or queued up somewhere behind the scenes (it is but I won't explain that part here.) When a thread calls a method, that method is ran to completion before any other methods can be ran which is why long running methods are preferred to be dispatched to other threads to prevent the application from freezing. In order to break a single method up into separate queues we need to do some fancy programming OR you can put the async signature on the method. This tells the compiler that at some point the method can be broken up into other methods and placed in a queue to be ran later.
If that makes sense then you're already figuring out what await does... await tells the compiler that this is where the method is going to be broken up and scheduled to run later. This is why you can use the async keyword without the await keyword; although the compiler knows this and warns you. await does all this for you by use of a Task.
How does await use a Task tell the compiler to schedule the rest of the method? When you call await Task the compilers calls the Task.GetAwaiter() method on that Task for you. GetAwaiter() return a TaskAwaiter. The TaskAwaiter implements two interfaces ICriticalNotifyCompletion, INotifyCompletion. Each has one method, UnsafeOnCompleted(Action continuation) and OnCompleted(Action continuation). The compiler then wraps the rest of the method (after the await keyword) and puts it in an Action and then it calls the OnCompleted and UnsafeOnCompleted methods and passes that Action in as a parameter. Now when the Task is complete, if successful it calls OnCompleted and if not it calls UnsafeOnCompleted and it calls those on the same thread context used to start the Task. It uses the ThreadContext to dispatch the thread to the original thread.
Now you can understand that neither async or await execute any Tasks. They simply tell the compiler to use some prewritten code to schedule all of it for you. In fact; you can await a Task that's not running and it will await until the Task is executed and completed or until the application ends.
Knowing this; lets get hacky and understand it deeper by doing what async await does manually.
Using async await
using System;
using System.Threading.Tasks;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Test();
Console.ReadKey();
}
public static async void Test()
{
Console.WriteLine($"Before Task");
await DoWorkAsync();
Console.WriteLine($"After Task");
}
static public Task DoWorkAsync()
{
return Task.Run(() =>
{
Console.WriteLine($"{nameof(DoWorkAsync)} starting...");
Task.Delay(1000).Wait();
Console.WriteLine($"{nameof(DoWorkAsync)} ending...");
});
}
}
}
//OUTPUT
//Before Task
//DoWorkAsync starting...
//DoWorkAsync ending...
//After Task
Doing what the compiler does manually (sort of)
Note: Although this code works it is meant to help you understand async await from a top down point of view. It DOES NOT encompass or execute the same way the compiler does verbatim.
using System;
using System.Threading.Tasks;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Test();
Console.ReadKey();
}
public static void Test()
{
Console.WriteLine($"Before Task");
var task = DoWorkAsync();
var taskAwaiter = task.GetAwaiter();
taskAwaiter.OnCompleted(() => Console.WriteLine($"After Task"));
}
static public Task DoWorkAsync()
{
return Task.Run(() =>
{
Console.WriteLine($"{nameof(DoWorkAsync)} starting...");
Task.Delay(1000).Wait();
Console.WriteLine($"{nameof(DoWorkAsync)} ending...");
});
}
}
}
//OUTPUT
//Before Task
//DoWorkAsync starting...
//DoWorkAsync ending...
//After Task
LESSON SUMMARY:
Note that the method in my example DoWorkAsync() is just a function that returns a Task. In my example the Task is running because in the method I use return Task.Run(() =>…. Using the keyword await does not change that logic. It's exactly the same; await only does what I mentioned above.
If you have any questions just ask and I'll be happy to answer them.
With starting you start a task. That means it might be picked up for execution by whatever Multitasaking system is in place.
With waiting, you wait for one task to actually finish before you continue.
There is no such thing as a Fire and Forget Thread. You always need to come back, to react to exceptions or do somethings with the result of the asynchronous operation (Database Query or WebQuery result, FileSystem operation finished, Dokument send to the nearest printer pool).
You can start and have as many task running in paralell as you want. But sooner or later you will require the results before you can go on.

How to make this sequence printed asynchronously? [duplicate]

Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine in my foreach and when I have entered the continuation task, data keeps coming in from my previous Tasks that aren't really finished.
What am I doing wrong here?
You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
You should not wrap your code in Task before passing to Parallel.ForEach.
You can just await Task.WhenAll instead of using ContinueWith.
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.
Just also add a try-catch block around the Task.WhenAll
NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.
try
{
Task.WaitAll(tasks.ToArray());
}
catch(AggregateException ex)
{
foreach (Exception inner in ex.InnerExceptions)
{
Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
}
}

Measuring performance gains with async-await [duplicate]

I have a Windows Service that reads from multiple MessageQueue instances. Those messagequeues all run their own Task for reading messages. Normally, after reading a message, the work of an I/O database is done. I've found articles claiming it's a good idea to use async on I/O operations, because it would free up threads. I'm trying to simulate the performance boost of using async I/O opertations in a Console application.
The Console application
In my test environment, I have 10 queues. GetQueues() returns 10 different MessageQueue instances.
static void Main(string[] args)
{
var isAsync = Console.ReadLine() == "Y";
foreach (var queue in queueManager.GetQueues())
{
var temp = queue;
Task.Run(() => ReceiveMessagesForQueue(temp, isAsync));
}
while (true)
{
FillAllQueuesWithMessages();
ResetAndStartStopWatch();
while(!AllMessagesRead())
{
Thread.Sleep(10);
}
Console.WriteLine("All messages read in {0}ms", stopWatch.ElapsedMilliseconds);
}
}
static async Task ReceiveMessagesForQueue(MessageQueue queue, bool isAsync)
{
while (true)
{
var message = await Task.Factory.FromAsync<Message>(queue.BeginReceive(), queue.EndReceive);
if (isAsync)
await ProcessMessageAsync(message);
else
ProcessMessage(message);
}
}
Async message processing
Uses await on Task.Delay(), so should release current Thread
static async Task ProcessMessageAsync(Message message)
{
await Task.Delay(1000);
BurnCpu();
}
Sync message processing
waits on Task.Delay(), so shouldn't release current Thread
static void ProcessMessage(Message message)
{
Task.Delay(1000).Wait();
BurnCpu();
}
In the end, results are equal. Am I missing something here?
Edit 1
I'm measuring overall time using stopWatch.ElapsedMilliseconds. I Fill all queues using FillAllQueuesWithMessages() with 10, 100, 10000 or more messages.
Edit 2
ReceiveMessagesForQueue() returns Task instead of void now.
Edit 3 (fix)
This test does show me performance improvement now. I had to make BurnCpu() take more time. While Task.Delay() is being awaited, BurnCPU() can use the released thread to process.
Using async-await doesn't speed up the time it takes to execute a single operation, it just means that you don't have a thread waiting doing nothing.
In your case Task.Delay will take a second no matter what but here:
Task.Delay(1000).Wait();
You have a thread that sits and waits for the second to end while here:
await Task.Delay(1000);
You don't. You are still asynchronously waiting (hence, await) but no thread is being used which means better scalability.
In async-await you get the performance boost because your app can do the same with less threads, or do more with the same threads. To measure that you need to have a lot of async operations concurrently. Only then will you notice that the async option utilizes CPU resources better than the synchronous one.
More info about freeing threads here There Is No Thread
You're still running each task in its own thread from the thread pool - as you're using the default task scheduler. If you want to see performance imporvement, you'll need to make sure several tasks are performed on the same thread.
Also, with 20 parallel tasks, you're probably not going to see any difference. Try it with 2,000 tasks.

Task stays in WaitingToRun state for abnormally long time

I've got a program that handles a variety of tasks running in parallel. A single task acts as a manager of sorts, making sure certain conditions are met before the next task is ran. However, I've found that sometimes a task will sit in the WaitingToRun state for a very long time. Here's the following code:
mIsDisposed = false;
mTasks = new BlockingCollection<TaskWrapper>(new ConcurrentQueue<TaskWrapper>());
Task.Factory.StartNew(() => {
while (!mIsDisposed) {
var tTask = mTasks.Take();
tTask.task.Start();
while (tTask.task.Status == TaskStatus.WaitingToRun) {
Console.WriteLine("Waiting to run... {0}", tTask.task.Id);
Thread.Sleep(200);
}
tTask.ready.Wait();
}
mTasks.Dispose();
});
DoWork();
DoWork();
DoWork();
DoWork();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWork();
TaskWrapper is very simply defined as:
private class TaskWrapper
{
public Task task { get; set; }
public Task ready { get; set; }
}
And tasks are only currently added in 2 places:
public void DoWork()
{
DoWorkAsync().Wait();
}
public Task DoWorkAsync()
{
ManualResetEvent next = new ManualResetEvent(false);
Task task = new Task(() => ActualWork(next));
Task ready = Task.Factory.StartNew(() => next.Wait());
mTasks.Add(new TaskWrapper() {
task = task,
ready = ready
});
return task;
}
Where ActualWork(next) calls next.Set().
This queues work and waits until next has been set before allowing the next work item to proceed. You can either wait for the entire task to finish before continuing by calling DoWork() or queue multiple tasks at once (which are supposed to run after next has been set).
However, when adding a task via DoWorkAsync(), after calling tTask.task.Start(), tTask.task sits in the WaitingToRun state for a loooong time (like 30 seconds to a minute), then magically starts running. I've monitored this using the while loop, and Waiting To Run... # will display for quite some time.
Calling DoWork() always runs immediately. I'm sure this has something to do with calling Wait on the task that is set to run.
I'm at a loss, here.
UPDATE:
I've managed to make the code work, but I'd still like to know why there's an issue in the first place.
After some experimental changes, I've managed to fix my own problem, but it's more of a "Oh, so I just can't do that" rather than a good fix. It turns out my problem was enqueuing tasks to run too quickly. By modifying DoWorkAsync() to no longer use Task.Factory.StartNew and changing tTask.ready.Wait() to tTask.ready.RunSynchronously I've managed to solve my issue.
Is there a reason the TaskScheduler is delaying the scheduling of my tasks? Am I saturating some underlying resources? What's going on here?
The threads will be run in the system's thread pool. The thread pool has a minimum number of threads available at all times (see ThreadPool.SetMinThreads()). If you try to create more than that many threads, a delay of approximately 500ms will be introduced between each new thread starting.
There is also a maximum number of threads in the thread pools (see ThreadPool.GetMaxThreads()), and if you reach that limit no new threads will be created; it will wait until an old thread dies before scheduling a new one (or rather, rescheduling the old one to run your new thread, of course).
You are unlikely to be hitting that limit though - it's probably over 1000.
Ok, I've just been faced with a similar issue. A bit of code that created and started a task ran, but the task never started (it just changed status to WaitingToRun)
Having tried the other options in this thread to no avail I thought about it a bit more, and realised that the code that was calling this method was itself called in a continuation task, that had been specified to run on the UI task scheduler (As it needed to update the UI)...
So something like
void Main()
{
var t1 = new Task(() => Console.WriteLine("hello, I'm task t1"));
t1.ContinueWith(t => CreateAndRunASubTask(), TaskScheduler.FromCurrentSynchronizationContext());
t1.Start();
Console.WriteLine("All tasks done with");
}
// Define other methods and classes here
public void CreateAndRunASubTask()
{
var tsk = new Task(() => Console.WriteLine("hello, I'm the sub-task"));
tsk.Start();
Console.WriteLine("sub-task has been told to start");
tsk.Wait();
// the code blocks on tsk.Wait() indefinately, the tsk status being "WaitingToRun"
Console.WriteLine("sub-task has finished");
}
The fix turned out to be pretty simple - when specifying the continuation task you need to specify the TaskContinuationOption: TaskContinuationOptions.HideScheduler
This has the effect of... (taken from the XML comment)
Specifies that tasks created by the continuation by calling methods
such as System.Threading.Tasks.Task.Run(System.Action) or
System.Threading.Tasks.Task.ContinueWith(System.Action{System.Threading.Tasks.Task})
see the default scheduler (System.Threading.Tasks.TaskScheduler.Default) rather
than the scheduler on which this continuation is running as the current scheduler.
ie (in my example)
t1.ContinueWith(t =>
CreateAndRunASubTask(),
System.Threading.CancellationToken.None,
TaskContinuationOptions.HideScheduler,
TaskScheduler.FromCurrentSynchronizationContext());
Hope this helps someone, as it stumped me for a good while!
Just faced similar issue.
I have a bunch of similar tasks running inifite loops, one of that tasks from time to time stays in WaitingToRun state permamently.
Creating tasks in that way did the trick for me:
_task = new Task(() => DoSmth(_cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
_task.Start();

Categories

Resources