Making more remoting calls than threads by making synchronous methods async - c#

I have a bunch of remoting calls that are all synchronous (3rd party library). Most of them take a lot of time so I'm not able to use them more often then about 5 to 10 times per second. This is too slow because I need to call them at least 3000 times every couple of minutes and many more if the services was stopped for some time. There is virtually no CPU work on the client. It gets the data, checks some simple conditions and makes another call that it has to wait for.
What would be the best way to make them async (call them in an async fashion - I guess I need some async wrapper) so that I can make more requests at the same time? Currently It's limited by the number of threads (which is four).
I was thinking about calling them with Task.Run but every article I read says it's for CPU bound work and that it uses thread-pool threads. If I get it correctly, with this approach I won't be able to break the thread limit, will I?. So which approach would actually fit best here?
What about Task.FromResult? Can I await such methods asynchronously in a greater number than there are threads?
public async Task<Data> GetDataTakingLotsOfTime(object id)
{
var data = remoting.GetData(id);
return await Task.FromResult(data);
}

I was thinking about calling them with Task.Run but every article I read says it's for CPU bound work and that it uses thread-pool threads.
Yes, but when you're stuck with a sync API then Task.Run() might be your lesser evil, especially on a Client.
Your current version of GetDataTakingLotsOfTime() is not really async. The FromResult() merely helps to suppress the Warning about that.
What about Task.FromResult? Can I await such methods asynchronously in a greater number than there are threads?
Not clear where your "number of threads" idea comes from but yes, starting a Task method and awaiting it later essentially runs it on the ThreadPool. But Task.Run is clearer in that respect.
Note that that does not depend on the async modifier of the method - async is an implementation detail, the caller only cares that it returns a Task.
Currently It's limited by the number of threads (which is four).
This needs some explaining. I don't get it.

You are executing a remote call, and your thread needs to wait idly for the result of the remote call. During this wait your thread could do useful things, like executing other remote calls.
Times when your thread is idly waiting for other processes to finish, like writing to a disk, querying a database or fetching information from the internet are typically situations where you'll see an async function next to a non-async function: Write and WriteAsync, Send and SendAsync.
If at the deepest level of your synchronous call you have access to an async version of the call, then your life would be easy. Alas it seems that you don't have such an async version.
Your proposed solution using Task.Run has the disadvantage of the overhead in starting a new thread (or running one from the thread pool).
You could lower this overhead by creating a workshop object. In the workshop, a dedicated thread (a worker), or several dedicated threads are waiting at one input point for an order to do something. The threads performs the task and posts the result at the output point.
Users of the workshop have one access point (front office?) where they post the request to do something, and await for the result.
For this I used System.Threading.Tasks.Dataflow.BufferBlock. Install Nuget package TPL Dataflow.
You can dedicate your workshop to accept only work to GetDataTakingLotsOfTime; I made my workshop generic: I accept every job that implements interface IWork:
interface IWork
{
void DoWork();
}
The WorkShop has two BufferBlocks: one to input work requests and one to output finished work. The workshop has a thread (or several threads) that wait at the input BufferBlock until a job arrives. Does the Work, and when finished posts the job to the output BufferBlock
class WorkShop
{
public WorkShop()
{
this.workRequests = new BufferBlock<IWork>();
this.finishedWork = new BufferBlock<IWork>();
this.frontOffice = new FrontOffice(this.workRequests, this.finishedWork);
}
private readonly BufferBlock<IWork> workRequests;
private readonly BufferBlock<IWork> finishedWork;
private readonly FrontOffice frontOffice;
public FrontOffice {get{return this.frontOffice;} }
public async Task StartWorkingAsync(CancellationToken token)
{
while (await this.workRequests.OutputAvailableAsync(token)
{ // some work request at the input buffer
IWork requestedWork = this.workRequests.ReceiveAsync(token);
requestedWork.DoWork();
this.FinishedWork.Post(requestedWork);
}
// if here: no work expected anymore:
this.FinishedWork.Complete();
}
// function to close the WorkShop
public async Task CloseShopAsync()
{
// signal that no more work is to be expected:
this.WorkRequests.Complete();
// await until the worker has finished his last job for the day:
await this.FinishedWork.Completion();
}
}
TODO: proper reaction on CancellationToken.CancellationRequested
TODO: proper reaction on exceptions thrown by work
TODO: decide whether to use several threads doing the work
FrontOffice has one async function, that accepts work, sends the work to the WorkRequests and awaits for the work to finish:
public async Task<IWork> OrderWorkAsync(IWork work, CancellationToken token)
{
await this.WorkRequests.SendAsync(work, token);
IWork finishedWork = await this.FinishedWork.ReceivedAsync(token);
return finishedWork;
}
So your process created a WorkShop object and starts one or more threads that will StartWorking.
Whenever any thread (inclusive your main thread) needs some work to be performed in async-await fashion:
Create An object that holds the input parameters and the DoWork function
Ask the WorkShop for the FrontOffice
await OrderWorkAsync
.
class InformationGetter : IWork
{
public int Id {get; set;} // the input Id
public Data FetchedData {get; private set;} // the result from Remoting.GetData(id);
public void DoWork()
{
this.FetchedData = remoting.GetData(this.Id);
}
}
Finally the Async version of your remote
async Task<Data> RemoteGetDataAsync(int id)
{
// create the job to get the information:
InformationGetter infoGetter = new InformationGetter() {Id = id};
// go to the front office of the workshop and order to do the job
await this.MyWorkShop.FrontOffice.OrderWorkAsync(infoGetter);
return infoGetter.FetchedData;
}

Related

Is Async Await in Console apps as useful as GUI and ASP.NET apps?

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

Is there a way to limit the number of parallel Tasks globally in an ASP.NET Web API application?

I have an ASP.NET 5 Web API application which contains a method that takes objects from a List<T> and makes HTTP requests to a server, 5 at a time, until all requests have completed. This is accomplished using a SemaphoreSlim, a List<Task>(), and awaiting on Task.WhenAll(), similar to the example snippet below:
public async Task<ResponseObj[]> DoStuff(List<Input> inputData)
{
const int maxDegreeOfParallelism = 5;
var tasks = new List<Task<ResponseObj>>();
using var throttler = new SemaphoreSlim(maxDegreeOfParallelism);
foreach (var input in inputData)
{
tasks.Add(ExecHttpRequestAsync(input, throttler));
}
List<ResponseObj> resposnes = await Task.WhenAll(tasks).ConfigureAwait(false);
return responses;
}
private async Task<ResponseObj> ExecHttpRequestAsync(Input input, SemaphoreSlim throttler)
{
await throttler.WaitAsync().ConfigureAwait(false);
try
{
using var request = new HttpRequestMessage(HttpMethod.Post, "https://foo.bar/api");
request.Content = new StringContent(JsonConvert.SerializeObject(input, Encoding.UTF8, "application/json");
var response = await HttpClientWrapper.SendAsync(request).ConfigureAwait(false);
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObject = JsonConvert.DeserializeObject<ResponseObj>(responseBody);
return responseObject;
}
finally
{
throttler.Release();
}
}
This works well, however I am looking to limit the total number of Tasks that are being executed in parallel globally throughout the application, so as to allow scaling up of this application. For example, if 50 requests to my API came in at the same time, this would start at most 250 tasks running parallel. If I wanted to limit the total number of Tasks that are being executed at any given time to say 100, is it possible to accomplish this? Perhaps via a Queue<T>? Would the framework automatically prevent too many tasks from being executed? Or am I approaching this problem in the wrong way, and would I instead need to Queue the incoming requests to my application?
I'm going to assume the code is fixed, i.e., Task.Run is removed and the WaitAsync / Release are adjusted to throttle the HTTP calls instead of List<T>.Add.
I am looking to limit the total number of Tasks that are being executed in parallel globally throughout the application, so as to allow scaling up of this application.
This does not make sense to me. Limiting your tasks limits your scaling up.
For example, if 50 requests to my API came in at the same time, this would start at most 250 tasks running parallel.
Concurrently, sure, but not in parallel. It's important to note that these aren't 250 threads, and that they're not 250 CPU-bound operations waiting for free thread pool threads to run on, either. These are Promise Tasks, not Delegate Tasks, so they don't "run" on a thread at all. It's just 250 objects in memory.
If I wanted to limit the total number of Tasks that are being executed at any given time to say 100, is it possible to accomplish this?
Since (these kinds of) tasks are just in-memory objects, there should be no need to limit them, any more than you would need to limit the number of strings or List<T>s. Apply throttling where you do need it; e.g., number of HTTP calls done simultaneously per request. Or per host.
Would the framework automatically prevent too many tasks from being executed?
The framework has nothing like this built-in.
Perhaps via a Queue? Or am I approaching this problem in the wrong way, and would I instead need to Queue the incoming requests to my application?
There's already a queue of requests. It's handled by IIS (or whatever your host is). If your server gets too busy (or gets busy very suddenly), the requests will queue up without you having to do anything.
If I wanted to limit the total number of Tasks that are being executed at any given time to say 100, is it possible to accomplish this?
What you are looking for is to limit the MaximumConcurrencyLevel of what's called the Task Scheduler. You can create your own task scheduler that regulates the MaximumCongruencyLevel of the tasks it manages. I would recommend implementing a queue-like object that tracks incoming requests and currently working requests and waits for the current requests to finish before consuming more. The below information may still be relevant.
The task scheduler is in charge of how Tasks are prioritized, and in charge of tracking the tasks and ensuring that their work is completed, at least eventually.
The way it does this is actually very similar to what you mentioned, in general the way the Task Scheduler handles tasks is in a FIFO (First in first out) model very similar to how a ConcurrentQueue<T> works (at least starting in .NET 4).
Would the framework automatically prevent too many tasks from being executed?
By default the TaskScheduler that is created with most applications appears to default to a MaximumConcurrencyLevel of int.MaxValue. So theoretically yes.
The fact that there practically is no limit to the amount of tasks(at least with the default TaskScheduler) might not be that big of a deal for your case scenario.
Tasks are separated into two types, at least when it comes to how they are assigned to the available thread pools. They're separated into Local and Global queues.
Without going too far into detail, the way it works is if a task creates other tasks, those new tasks are part of the parent tasks queue (a local queue). Tasks spawned by a parent task are limited to the parent's thread pool.(Unless the task scheduler takes it upon itself to move queues around)
If a task isn't created by another task, it's a top-level task and is placed into the Global Queue. These would normally be assigned their own thread(if available) and if one isn't available it's treated in a FIFO model, as mentioned above, until it's work can be completed.
This is important because although you can limit the amount of concurrency that happens with the TaskScheduler, it may not necessarily be important - if for say you have a top-level task that's marked as long running and is in-charge of processing your incoming requests. This would be helpful since all the tasks spawned by this top-level task will be part of that task's local queue and therefor won't spam all your available threads in your thread pool.
When you have a bunch of items and you want to process them asynchronously and with limited concurrency, the SemaphoreSlim is a great tool for this job. There are two ways that it can be used. One way is to create all the tasks immediately and have each task acquire the semaphore before doing it's main work, and the other is to throttle the creation of the tasks while the source is enumerated. The first technique is eager, and so it consumes more RAM, but it's more maintainable because it is easier to understand and implement. The second technique is lazy, and it's more efficient if you have millions of items to process.
The technique that you have used in your sample code is the second (lazy) one.
Here is an example of using two SemaphoreSlims in order to impose two maximum concurrency policies, one per request and one globally. First the eager approach:
private const int maxConcurrencyGlobal = 100;
private static SemaphoreSlim globalThrottler
= new SemaphoreSlim(maxConcurrencyGlobal, maxConcurrencyGlobal);
public async Task<ResponseObj[]> DoStuffAsync(IEnumerable<Input> inputData)
{
const int maxConcurrencyPerRequest = 5;
var perRequestThrottler
= new SemaphoreSlim(maxConcurrencyPerRequest, maxConcurrencyPerRequest);
Task<ResponseObj>[] tasks = inputData.Select(async input =>
{
await perRequestThrottler.WaitAsync();
try
{
await globalThrottler.WaitAsync();
try
{
return await ExecHttpRequestAsync(input);
}
finally { globalThrottler.Release(); }
}
finally { perRequestThrottler.Release(); }
}).ToArray();
return await Task.WhenAll(tasks);
}
The Select LINQ operator provides an easy and intuitive way to project items to tasks.
And here is the lazy approach for doing exactly the same thing:
private const int maxConcurrencyGlobal = 100;
private static SemaphoreSlim globalThrottler
= new SemaphoreSlim(maxConcurrencyGlobal, maxConcurrencyGlobal);
public async Task<ResponseObj[]> DoStuffAsync(IEnumerable<Input> inputData)
{
const int maxConcurrencyPerRequest = 5;
var perRequestThrottler
= new SemaphoreSlim(maxConcurrencyPerRequest, maxConcurrencyPerRequest);
var tasks = new List<Task<ResponseObj>>();
foreach (var input in inputData)
{
await perRequestThrottler.WaitAsync();
await globalThrottler.WaitAsync();
Task<ResponseObj> task = Run(async () =>
{
try
{
return await ExecHttpRequestAsync(input);
}
finally
{
try { globalThrottler.Release(); }
finally { perRequestThrottler.Release(); }
}
});
tasks.Add(task);
}
return await Task.WhenAll(tasks);
static async Task<T> Run<T>(Func<Task<T>> action) => await action();
}
This implementation assumes that the await globalThrottler.WaitAsync() will never throw, which is a given according to the documentation. This will no longer be the case if you decide later to add support for cancellation, and you pass a CancellationToken to the method. In that case you would need one more try/finally wrapper around the task-creation logic. The first (eager) approach could be enhanced with cancellation support without such considerations. Its existing try/finally infrastructure is
already sufficient.
It is also important that the internal helper Run method is implemented with async/await. Eliding the async/await would be an easy mistake to make, because in that case any exception thrown synchronously by the ExecHttpRequestAsync method would be rethrown immediately, and it would not be encapsulated in a Task<ResponseObj>. Then the task returned by the DoStuffAsync method would fail without releasing the acquired semaphores, and also without awaiting the completion of the already started operations. That's another argument for preferring the eager approach. The lazy approach has too many gotchas to watch for.

async await for a single task at a time

During my job interview, I was given a task to create an asynchronous wrapper over some long running method, processing some data, but to create it so that only a single task could be running at a time. I was not very familiar with async/await pattern, so I did my best and wrote some mixup between task-style and event-style, so that my wrapper was holding a task currently being executed, and exposing a public method and a public event. Method took data to process as an argument, and if there was no task running, started one, if there was a task, it enqueued the data. Task was raising the public event upon completion, which was sending process results to subscribers and starting a new task if there is any enqueued.
So, as you could probably guess by that point, I failed an interview, but now that I did some research, I am trying to figure out how to properly do it (it should have also been thread-safe, but I was too busy worrying about that). So my question is, if I have
public class SynchronousProcessor
{
public string Process(string arg)
{
Thread.Sleep(1500); //Work imitation
return someRandomString;
}
}
public class AsynchronousWrapper
{
SynchronousProcessor proc = new SynchronousProcessor();
public async Task<string> ProcessAsync(string arg)
{
return Task.Run(() => proc.Process(arg));
}
}
, or something like this, how do I properly handle calls to ProcessAsync(string) if there is already a task executing?
Many job interview questions are asked for a purpose other than to see you write the code. Usually, questions are a bit vague specifically to see what clarifying questions you ask - your questions determine how well you do. Writing code on a whiteboard is secondary at best.
I was given a task to create an asynchronous wrapper over some long running method, processing some data
First question: is this long-running method asynchronous? If so, then there would not be a need for Task.Run. But if not...
Followup question: if it's not asynchronous, should it be? I.e., is it I/O-based? If so, then we could invest the time to make it properly asynchronous. But if not...
Followup question: if we need a task wrapper (around CPU-based code or around blocking I/O code), is the environment agreeable to a wrapper? I.e., is this a desktop/mobile app and not code that would be used in ASP.NET?
create it so that only a single task could be running at a time.
Clarifying questions: if a second request comes in when one is already running, does the second request "queue up"? Or would it "merge" with an existing request? If merging, do they need to "key" off of the input data - or some subset of the input data?
Every one of these questions change how the answer is structured.
exposing a public method and a public event.
This could be what threw it. Between Task<T> / IProgress<T> and Rx, events are seldom needed. They really only should be used if you're on a team that won't learn Rx.
Oh, and don't worry about "failing" an interview. I've "failed" over 2/3 of my interviews over the course of my career. I just don't interview well.
It depends on how fancy you want to get. One simple way is to store a task, and chain the subsequent tasks (with a bit of synchronization):
public class AsynchronousWrapper
{
private Task previousTask = Task.CompletedTask;
private SynchronousProcessor proc = new SynchronousProcessor();
public Task<string> ProcessAsync(string arg)
{
lock (proc)
{
var task = previousTask.ContinueWith(_ => proc.Process(arg));
previousTask = task;
return task;
}
}
}
As #MickyD already said, you need to know the Best Practices in Asynchronous Programming to solve such problems right way. Your solution has a code smell as it provide async wrapper with Task.Run for a synchronous code. As you were asked about the library development, it will be quite impacting your library consumers.
You have to understand that asynchronous isn't multithreading, as it can be done with one thread. It's like waiting for a mail - you don't hire a worker to wait by the mailbox.
Other solutions here aren't, well, async, because break other rule for async code: do not block async action, so you should avoid the lock construct.
So, back to your problem: if you face a task which states
only a single task could be running at a time
It is not about the lock (Monitor), it is about Semaphore(Slim). If for some reason in future you'll need to improve your code so more than one task can be executed simultaneously, you'll have to rewrite your code. In case of Semaphore usage you'll need to change only one constant. Also it has an async wrappers for waiting methods
So your code can be like this (note that the Task.Run is removed, as it is a client responsibility to provide an awaitable):
public class AsynchronousWrapper
{
private static SemaphoreSlim _mutex = new SemaphoreSlim(1);
public async Task<T> ProcessAsync<T>(Task<T> arg)
{
await _mutex.WaitAsync().ConfigureAwait(false);
try
{
return await arg;
}
finally
{
_mutex.Release();
}
}
}

Understanding fire and forget when using infinite loops

Can someone tell me what the best practice/proper way of doing this is?
I'm also using WPF, not a console or ASP.NET.
Using Listener to accept clients and spin off a new "thread" for each client that handles all the I/O and Exception catching for that client.
Method 1: Fire and forget, and just throw it into a variable to get rid of the warning.
public static async Task Start(CancellationToken token)
{
m_server = TcpListener.Create(33777);
m_server.Start();
running = true;
clientCount = 0;
// TODO: Add try... catch
while (!token.IsCancellationRequested)
{
var client = await m_server.AcceptTcpClientAsync().ConfigureAwait(false);
Client c = new Client(client);
var _ = HandleClientAsync(c);
}
}
Here's the Client Handler code:
public static async Task HandleClientAsync(Client c)
{
// TODO: add try...catch
while (c.connected)
{
string data = await c.reader.ReadLineAsync();
// Now we will parse the data and update variables accordingly
// Just Regex and some parsing that updates variables
ParseAndUpdate(data);
}
}
Method 2: The same thing... but with Task.Run()
var _ = Task.Run(() => HandleClientAsync());
Method 3: an intermediate non async function (doubt this is good. Should be Async all the way)
But this at least gets rid of the squiggly line without using the variable trick which kinda feels dirty.
while (!token.IsCancellationRequested)
{
var client = await m_server.AcceptTcpClientAsync().ConfigureAwait(false);
Client c = new Client(client);
NonAsync(c);
}
public static void NonAsync(VClient vc)
{
Task.Run(() => HandleClientAsync(vc));
}
Method 4: Make HandleClientAsync an Async void instead of Async Task (really bad)
public static async Task HandleClientAsync(Client c)
// Would change to
public static async Void HandleClientAsync(Client c)
Questions:
Is it any better to use Task.Run() When doing a fire and forget task?
Is it just accepted that you need to use the var _ = FireAndForget() trick to do fire and forget? I could just ignore the warning but something feels wrong about it.
If I wanted to update my UI from a Client, how would I do that? Would I just use a dispatcher?
Thanks guys
I've never been a fan of background workers which you expect to run for a long time, being run in a task. Tasks get scheduled to run on threads drawn from a pool. As you schedule these long running tasks, the thread pool gets smaller and smaller. Eventually all of the threads from the pool are busy running your tasks, and things get really slow and unmanageable.
My recommendation here? Use the Thread class and manage them yourselves. In this way, you keep your thread pool and the overhead for for tasks out of the picture.
Addendum - Producer Consumer Model
Another interesting question to consider: Do you really need a thread for every client? Threads are reasonably costly to create and maintain in terms of memory overhead, and if your client interaction is such that the client threads spend the vast majority of their time waiting around on something to do, then perhaps a producer consumer model is more suited to your use case.
Example:
Client connects on listening thread, gets put in a client queue
Worker thread responsible for checking to see if the clients need anything comes along through that queue every so often and checks - does the client have a new message to service? If so, it services all messages the client has, then moves on
In this way, you limit the number of threads working to just the number needed to manage the message queue. You can even get fancy and add worker threads dynamically based on how long its been since all the clients have been serviced.
If you insist
If you really like what you have going, I suggest refactoring what youre doing a bit so that rather than HandleClientAsync you do something more akin to CreateServiceForClient(c);
This could be a synchronous method that returns something like a ClientService. ClientService could then create the task that does what your HandleClientAsync does now, and store that task as a member. It could also provide methods like
ClientService.WaitUntilEnd()
and
ClientService.Disconnect() (which could set a cancellation token, also stored as a member variable)

multithreading in regards toTask, async, and await

I have the following code and just want to make sure I have the concept of multithreading down on a high level.
public async Task<List<Category>> GetProjectsByCategoryIDAsync(Int16 categoryid)
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
var category = await DbContext.Categories.Include("Projects").Where(p => p.CategoryID == categoryid).ToListAsync();
return category;
}
}
catch (Exception)
{
throw;
}
}
It is my understanding of the following:
async - declares a method to run asynchounously instead of
synchrounously.
Task - declares a method to run as a task on a single thread
await - the task waits for the operation to complete.
Where I am a little fuzzy about is the await keyword. Obviously, the benefit of asynchrounous programming is that the method supposedly doesn't have to wait for the task to complete before another request comes in right behind it. But with the await keyword, the task waits until the operation is finished.
With synchrounous programming, everything is processed in a sequential pattern.
How does this methodology allow for requests to come in simultaneously and be executed in a much faster fashion than synchronous programming??
I just need a high level explanation to get the concept down.
Thanks so much in advance.
Consider the following code:
public async Task DoSomething()
{
Console.WriteLine("Begin");
int i = await DoSomethingElse();
Console.WriteLine("End " + i);
}
public Task<int> DoSomethingElse()
{
return new Task<int>(() =>
{
// do heavy work
Thread.Sleep(1000);
return 1;
});
}
With synchrounous programming, everything is processed in a sequential
pattern.
The code above is asynchronous, but is still sequential. The difference between that code and its synchronous version (e.g., public int DoSomethingElse) is that when you await DoSomethingElse, the main thread will be freed to do other work, instead of blocking waiting for DoSomethingElse to complete.
What actually happens is: your async DoSomething method will run on thread A and be broken in two.
the first part will print "Begin" and make an async call, and then return.
the second part will print "End"
After the first part of the method executes, Thread A will be free to do other work.
Meanwhile, Thread B will be executing the lambda expression that does some heavy work.
Whenever Thread B completes, the second part of your method will be scheduled to run on Thread A, and "End" will be printed.
Notice that, while Thread B was executing the heavy work, Thread A was free to do other stuff.
How does this methodology allow for requests to come in simultaneously
and be executed in a much faster fashion than synchronous
programming??
In frameworks such as ASP.NET MVC, your application has a finite number of threads available to handle incoming requests (lets call these "request threads"). By delegating heavy work to other threads and awaiting, your request threads will be free to handle more incoming requests while heavy work is being done.
This diagram, although complex, illustrates the execution/suspension flow of threads executing asynchronous work:
Notice how at step 6 the thread was yielded, and then step 7 resumed the execution of the method.
As you can see, the await keyword effectively breaks the method in two.

Categories

Resources