Let's say we have an entity Team with fields Id, Name, Points and CompetitionId.
Based on this entity, I have a list saved in memory, with aggregate data for each team.
When I add some results, some lines in the table Teams, I want also to update this list, but not to wait for its result.
public async Task AddResults(List<Team> teams) {
await context.AddRange(teams);
await inMemoryService.SetRanking();
}
Inside of SetRankings method I get the teams lines from context and build the aggregate data. But I don't want to wait for that to be finished because is a long process (take ~ 10 minutes and will be increased each time). For that, I tried two methods:
1: to not use await keyword:
_ = inMemoryService.SetRanking(); this works only because I'll not wait for the task to be completed. BUT, the new aggregated list from memory will be created on the another thread (I think), and when I'll try to get the data, I'll receive the old one.
2: using ConfigureAwait with false value:
await inMemoryService.SetRanking().ConfigureAwait(false) here, the request is still locked until this task is completed.
How can I solve this? thx
The best way to not wait for a task to be completed is to give that task to another piece of code.
AddResults could add the work to a queue and return. Then, another piece of code processes that work.
The queue itself can be:
and in-memory queue,
a queue service that your chose cloud provider offers,
even a database table.
The 'another piece of code' which monitors and processes the queue could be:
a dedicated long running task in the same app
another service (e.g Azure Function with a queue trigger)
Related
I have built a MQTT client that listens for certain status data. For each message I run a method which can take a while (up to 1 second). Since a lot of messages can arrive at once, I want to run the whole thing in parallel. My problem now is, when I receive a message belonging to topic A, I want to make sure that the previous task belonging to topic A has already finished before I start the new one. But I also need to be able to receive new messages during the time I am waiting for Task A to finish and add them to the queue if necessary. Of course, if the new message belongs to topic B, I don't care about the status of task A and I can run this method call in parallel.
In my mind, this is solved with a kind of dictionary that has different queues.
What about to use a lock on an object related to the topic?
When a new item come in the system you could retrieve/create a lock object from a ConcurrentDictionary and then you could use this object to lock the execution.
something like this.
static ConcurrentDictionary<string,object> _locksByCategory =
new ConcurrentDictionary<string,object>();
async void ProcessItem(ItemType item) {
var lockObject = _locksByCategory(item.Category, new object(), (k, o) => o);
lock (lockObject) {
// your code
}
}
This isn't a production ready solution but could help to start with.
I don't know exactly how you would do it, but it goes along the lines of:
On startup, create a (static? singleton?) Dictionary<Topic, ConcurrentQueue> and for each topic create a thread that does the following:
Wrap the ConcurrentQueue in a BlockingCollection
infinitely loop with BlockingCollection.Take at the start of the loop. This should block until an item is ready, execute the rest of the loop and listen for more items afterwards.
Whenever a message comes in, add it to the corresponding ConcurrentQueue.
I am currently learning C# Async/Await feature and can see its usefulness in GUI and web apps but I am still trying to figure out its real usefulness in Console apps. Can you give an example that drives home the point?
Async allows running more code until tasks are awaited, so if there is more code that can be run simultaniously (meaning - it is not dependent of the other task), it can start right away.
for example:
public async Task<string> GetUserFullNameAsync(string firstName)
{
return await GetUserFullNameAsyncInner(firstName); // gets user name from db in an async fashion - takes 4 seconds
}
public async Task<DateTime> GetFlightTimeAsync(string filghtName)
{
return await GetFlightTimeAsyncInner(filghtName); // gets filget time from db in as async fashion - takes 4 seconds
}
public async Task<UserDetails> GetUserDetailsAsync(string userFullName)
{
return await GetUserDetailsAsyncInner(name); // gets user details by its full name from db in an async fashion - takes 4 seconds
}
lets look at this function:
public async <UserDetails> GetUserDetails(string firstName)
{
var userFullName = await GetUserDetailsAsync(firstName);
return await GetUserDetailsAsync(userFullName);
}
notice how GetUserDetailsAsync is dependent of getting the full name first, by using GetUserDetailsAsync.
So if you need to get the UserDetails object, you are dependent of waitig for the GetUserDetailsAsync to finish. that may take some time - especailly for heavier actions like video processing and such.
In this example - 4 seconds for the first function + 4 seconds for the seconds = 8 seconds.
now lets look at this second function:
public async <FlightDetails> GetUserFlightDetails(string firstName, string flightName)
{
var userFullNameTask = GetUserDetailsAsync(firstName);
var flightTimeTask = GetFlightTimeAsync(flightName);
await Task.WhenAll(userFullNameTask, flightTimeTask);
return new FlightDetails(await userFullNameTask, await flightTimeTask);
}
Notice that GetFlightTimeAsync is not dependent on any other function, so if you need say that user full name and flight time, you can do it in a parallel way, so both actions are processed in the same time - hence the total time to wait is faster than getting the full name and then getting the flight time.
4 seconds for the first function + 4 seconds for the second - in a parallel way < 8 seconds.
Let's look at a different angle on the asynchronous programming than just a way of doing things in parallel. Yes, you can run tasks in parallel but you can find so much code that is using await/async but it is waiting on every asynchronous execution.
What is the point of doing so? There is no parallel execution there...
It is everything about making better use of available system resources, especially threads.
Once the execution reaches an asynchronous code the thread can be released and the threads are limited system resources. By releasing the thread when it’s idling for an IO-bound work to complete, it can be used to serve another request. It also protects against usage bursts since the scheduler doesn’t suddenly find itself starved of threads to serve new requests.
Choosing an async operation instead of a synchronous one doesn't speed up the operation. It will take the same amount of time (or even more). It just enables that thread to continue executing some other CPU bound work instead of wasting resources.
If you have any I/O-bound needs (such as requesting data from a network, accessing a database, or reading and writing to a file system), you'll want to utilize asynchronous programming. No matter if the application is a console one or not.
Bonus: If you are wondering: "Ok, my application released the thread but there must be some other thread that is really doing the wait!" have a look at this article from Stephen Cleary
My application is using Hangfire for background job processing.
I create the background jobs as follows:
var parentJobId = _backgroundJobClient.Enqueue<IMyService>(x => x.ParentMethod(id));
_backgroundJobClient.ContinueWith<IMyService>(parentJobId, x => x.ChildMethod(id));
_backgroundJobClient.Enqueue<IMyService>(x => x.OtherMethod1(id));
_backgroundJobClient.Enqueue<IMyService>(x => x.OtherMethod2(id));
Those methods are defined in the service as follows:
public interface IMyService
{
[Queue(HangfireQueuePriority.Default)]
void ParentMethod(int id);
[Queue(HangfireQueuePriority.Default)]
void ChildMethod(int id);
[Queue(HangfireQueuePriority.Default)]
void OtherMethod1(int id);
[Queue(HangfireQueuePriority.Critical)]
void OtherMethod2(int id);
}
I'd like the ChildMethod to be running as soon as the parent job has finished.
My understanding of ContinueWith is that the child job runs after the parent job, but it is not specified in the Hangfire documentation how soon the child task will run.
My question is what is the "priority" of the child task over other tasks in a queue?
Is there a chance that any task defined in the queue will run between the ParentMethod and the ChildMethod? e.g. OtherMethod1 or OtherMethod2
My question is what is the "priority" of the child task over other
tasks in a queue?
All jobs in critical queues will be fetched first before default queues regardless of level of concurrency.
Is there a chance that any task defined in the queue will run between
the ParentMethod and the ChildMethod? e.g. OtherMethod1 or
OtherMethod2
Technically speaking based on my first answer to your first queues all jobs in critical queue will be fetched first and that will include your OtherMethod2. Now all remaining jobs are in Defaults Queue and by default Hangfire is setup to execute jobs in Concurrently base on available number of Worker. Meaning there is a chance that OtherMethod1 can run between ParentMethod and ChildMethod because they all under Default Queues.
For this issue, I use 2 hangfire servers.
The first is using queues like this "Continue,Default"
The second like this "Default,Continue"
your continue with has to be in the Continue queue.
So with this, when a task come in Continue queue, if the first is occupied, the second server take it, even if it's occupied with default job.
I use this because when i have a batch with thousands of enqueue and thousands of continuewith, i want the 2 queues to run in parallel.
I am writing a multi player game server and am looking at ways the new C# async/await features can
help me. The core of the server is a loop which updates all the actors in the game as fast as it
can:
while (!shutdown)
{
foreach (var actor in actors)
actor.Update();
// Send and receive pending network messages
// Various other system maintenance
}
This loop is required to handle thousands of actors and update multiple times per second to keep the
game running smoothly. Some actors occasionally perform slow tasks in their update functions, such
as fetching data from a database, which is where I'd like to use async. Once this data is retrieved
the actor wants to update the game state, which must be done on the main thread.
As this is a console application, I plan to write a SynchronizationContext which can dispatch
pending delegates to the main loop. This allows those tasks to update the game once they complete
and lets unhandled exceptions be thrown into the main loop. My question is, how do write the async
update functions? This works very nicely, but breaks the recommendations not to use async void:
Thing foo;
public override void Update()
{
foo.DoThings();
if (someCondition) {
UpdateAsync();
}
}
async void UpdateAsync()
{
// Get data, but let the server continue in the mean time
var newFoo = await GetFooFromDatabase();
// Now back on the main thread, update game state
this.foo = newFoo;
}
I could make Update() async and propogate the tasks back to the main loop, but:
I don't want to add overhead to the thousands of updates that will never use it.
Even in the main loop I don't want to await the tasks and block the loop.
Awaiting the task would cause a deadlock anyway as it needs to complete on the awaiting thread.
What do I do with all these tasks I can't await? The only time I might want to know they've all
finished is when I'm shutting the server down, but I don't want to collect every task generated by
potentially weeks worth of updates.
My understanding is that the crux of it is that you want:
while (!shutdown)
{
//This should happen immediately and completions occur on the main thread.
foreach (var actor in actors)
actor.Update(); //includes i/o bound database operations
// The subsequent code should not be delayed
...
}
Where the while loop is running in your main console thread. This is a tight single-threaded loop. You could run the foreach in parallel, but then you would still be waiting for the longest running instance (the i/o bound operation to get the data from the database).
await async is not the best option within this loop, you need to run these i/o database tasks on a thread pool. On the thread pool async await would be useful to free up pool threads.
So, the next question is how to get these completions back to your main thread. Well, it seems like you need something equivalent to a message pump on your main thread. See this post for information on how to do that, though that may be a bit heavy handed. You could just have a completion queue of sorts that you check on the main thread in each pass through your while Loop. You would use one of the concurrent data structures to do this so that it is all thread safe then set Foo if it needs to be set.
It seems that there is some room to rationalise this polling of actors and threading, but without knowing the details of the app it is hard to say.
A couple of points: -
If you do not have a Wait higher up on a task, your main console thread will exit and so will your application. See here for details.
As you have pointed out, await async does not block the current thread, but it does mean that the code subsequent to the await will only execute on completion of the await.
The completion may or may not be completed on the calling thread. You have already mentioned Synchronization Context, so I won't go into the details.
Synchronization Context is null on a Console app. See here for information.
Async isn't really for fire-and-forget type operations.
For fire and forget you can use one of these options depending on your scenario:
Use Task.Run or Task.StartNew. See here for differences.
Use a producer/consumer type pattern for the long running scenarios running under your own threadpool.
Be aware of the following: -
That you will need to handle the exceptions in your spawned tasks / threads. If there are any exceptions that you do not observe, you may want to handle these, even just to log their occurence. See the information on unobserved exceptions.
If your process dies while these long running tasks are on the queue or starting they will not be run, so you may want some kind of persistence mechanism (database, external queue, file) that keeps track of the state of these operations.
If you want to know about the state of these tasks, then you will need to keep track of them in some way, whether it is an in memory list, or by querying the queues for your own thread pool or by querying the persistence mechanism. The nice thing about the persistence mechanism is that it is resilient to crashes and during shutdown you could just close down immediately, then pick up where you ended up when you restart (this of course depends on how critical it is that the tasks are run within a certain timeframe).
First, I recommend that you do not use your own SynchronizationContext; I have one available as part of my AsyncEx library that I commonly use for Console apps.
As far as your update methods go, they should return Task. My AsyncEx library has a number of "task constants" that are useful when you have a method that might be asynchronous:
public override Task Update() // Note: not "async"
{
foo.DoThings();
if (someCondition) {
return UpdateAsync();
}
else {
return TaskConstants.Completed;
}
}
async Task UpdateAsync()
{
// Get data, but let the server continue in the mean time
var newFoo = await GetFooFromDatabase();
// Now back on the main thread, update game state
this.foo = newFoo;
}
Returning to your main loop, the solution there isn't quite as clear. If you want every actor to complete before continuing to the next actor, then you can do this:
AsyncContext.Run(async () =>
{
while (!shutdown)
{
foreach (var actor in actors)
await actor.Update();
...
}
});
Alternatively, if you want to start all actors simultaneously and wait for them all to complete before moving to the next "tick", you can do this:
AsyncContext.Run(async () =>
{
while (!shutdown)
{
await Task.WhenAll(actors.Select(actor => actor.Update()));
...
}
});
When I say "simultaneously" above, it is actually starting each actor in order, and since they all execute on the main thread (including the async continuations), there's no actual simultaneous behavior; each "chuck of code" will execute on the same thread.
I highly recommend watching this video or just taking a look at the slides:
Three Essential Tips for Using Async in Microsoft Visual C# and Visual Basic
From my understanding what you should probably be doing in this scenario is returning Task<Thing> in UpdateAsync and possibly even Update.
If you are performing some async operations with 'foo' outside the main loop what happens when the async part completes during a future sequential update? I believe you really want to wait on all your update tasks to complete and then swap your internal state over in one go.
Ideally you would start all the slow (database) updates first and then do the other faster ones so that the entire set is ready as soon as possible.
I'm putting together a simple C# app where a user types commands into a "command bar" and the results are fetched in real time.
For example I could type, google stackoverflow, and it sends an API call off to google, fetches each of the results and displays them in the ui.
Currently I fire off the "search" method if a user pauses for more than 1/4 of a second on typing, so if you paused in the middle it could fire google stack and google stackoverflow.
Now in reality the api is doing a (rather slow) database query and this causes the ui to lock up while the first search completes, before it tries to start on the second search.
Is there a simple (C# 4.0) way to run the search call in a separate thread that I can then cancel/abort if the user continues typing?
e.g.
Task<string> thread;
string getSearchResults(string input) {
... Do some work ...
}
string userPaused(string search) {
if(this.thread.isRunning()) this.thread.Kill();
this.thread = new Task<String>(getSearchResults(string input);
return this.thread.result();
}
I've looked at the Tasks api and it doesn't look as if you can kill a task in the middle of work, it suggests using a while look and passing a shouldStop boolean, however during an API call to download the results there is no while loop.
The Threading documentation however points you to tasks if you need to get the return value.
What you may do with Tasks is to create them, and then cancel when not needed any more. If you can't cancel operation you are doing (like database query) - you can always cancel before results get returned. Your code may be something like this (not tested, just a draft):
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Factory.StartNew(() =>
{
ct.ThrowIfCancellationRequested();
var result = Database.GetResult(); // whatever database query method you use.
ct.ThrowIfCancellationRequested();
return result;
}, tokenSource2.Token);
So as you can see it will query database and return value when no cancellation requested, but if you will try to cancell the task - it will not return value but rather throw OperationCanceledException you need to catch. For details visit MSDN Task Cancellation, but I think this should give you an idea. Don't worry about big task number - if your query is not very slow it won't matter - user will not be able to trigger so many searches. If you have asynchronous way of querying database - you can improve this code a bit more, but that also shouldn't be too hard.