C# Channels Explained (System.Threading.Channels)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome everyone today we're gonna be talking about channels come from a language like golang you are gonna be familiar with channels because that's all they have there to solve their concurrency and parallelism problems in c-sharp channels is a relatively new feature and the primary problem the channels solve is a producer/consumer problem right so if you can find a model mental model in your code that something is producing something and then another thing has to consume it you pretty much want to use a channel because that's a very good solution for it and a lot of cloud providers also they provide these channel solutions pub/sub hughes publisher subscriber cues which is essentially a channel so it's a quite frequently used technology and how it works it can be a benefit right so first of all we're gonna start with a quick example of why you might want to use a channel then we're gonna jump in into how it's made essentially at the more of a higher level view because in the low level the channel is made using more lower level concepts to make it more efficient but we'll just have an overview it and then we will go into visual studio into an asp.net core project and we're gonna see some actual use cases for it okay so let's go ahead and get started so a simple example here is we want to send a notification and this might entail something like a slight delay right we will have to communicate with some external service and let's go ahead get the away derp and get result okay so this is a blocking operation and it's a blocking operation not in a sense that I'm blocking a thread yes I can make this asynchronous but it's a blocking operation in a sense of a user making a request to your service right so imagine if a user makes a request to your service and part of the request has to send out a notification if as part of a response to the user the user has to wait for the notification to get created he's gonna be waiting right it doesn't matter well thread completes it he's gonna be waiting so this is what we're simulating here so we want to just go ahead and send notification and I'm obviously not printing anything so let's go ahead and just to dump the I here so you're not familiar I've been using a link pad for my lessons recently link is in the description it's really awesome piece of kit oh yeah as you can see what happens is the sequential execution right which is pretty much what should happen right you make a request to the server you update the date at the product the product in the database and then as part of that somebody gets notified right but because it needs to go off to some service to send a notification that's user still has to wait for the request so what you could do is you could put this end notification in a fire-and-forget task right so you're just gonna say alright send off notification I don't care when that finishes etc so what you will be tempted to do you're just gonna go ahead and put run here right and well everything sort of completed real quickly and then let's say just so we can get a visual on these tasks getting completed right here we can see that I'm just being blasted out right so what did we simulate here we we essentially simulated 10 people get make a request or you make a request 10 times and all these requests complete instantly but then after some time the notification gets sent ok so the problem with the fight of this fire-and-forget approach is in the scope ok so let's say this is going to be in a service and usually the way you resolve services is you do dependency injection right so you dependency inject into a service and then in this service the send notification function is going to consume one of the services that was injected because we exit this scope before the notification is actually finished sending the dependency injection is going to dispose of that service that was injected once that service is disposed when the sudden send notification is gonna try to consume it that's when the trouble is gonna arise ok and this is just gonna crush me like the service no longer exists right so this is where you might want to use a channel where you basically say put a message of what you want to send in a channel and and when a service is ready you can pick it up and also another problem with this solution let's say you are running on a one processor machine right and you have let's say 20 or a hundred users one day right and they all generate it at 10 notifications each ok let's say it's a because it's maybe a slow processor it might say take one second to send a notification you're essentially flooding the task you with these fire-and-forget tasks and at some point your server is gonna be slow to respond anyway right so you might want to limit the amount of tasks that get processed at the same time and a child can help with that as well right because it is it does implement a queue so before going into the visual studio examples what I want to do is I want to go ahead and implement a channel ourselves right one real-world problem I solved when I implemented a channel myself before channels actually existed in c-sharp is the video processing problem so a video video processing was a long-running task and kind of like YouTube where you upload a video and then you can just even close the browser and your video is still processing into different qualities that's essentially what they do they basically they take your task they put it on it you or a channel and then something reads off a queue and starts processing your video okay and I essentially did the same thing and yeah I'm just gonna show you how I accomplished that so this is gonna include knowledge of the semaphore so if you haven't watched that video watch my previous video if you know what a semaphore is you're good to go so a channel comprises of two real things is you want to be able to read from a channel and you want to be able to write to a channel okay so let's go ahead and make two interfaces okay so public where we want to read and I gotta say interface alright and public interphase I right okay so what are we gonna write we are going to write some kind of type right and we want to be able to also read that type okay so let's go ahead and push something into the channel okay and it's generally any message right it doesn't matter what it is it's some kind of message and the whole thing about channels is that this message kind of what how we have a service in the scope of this main function that would be consumed by the send notification instead of depending on the memory in this service of having another service injected into that right so it's kind of some kind of state of that service that needs to be or this function to be able to consume that service that was injected right so it's a stateless memory of that service here we don't depend on the state we rather say this is what's needed to produce the notification this message and we push it into the channel and then something else goes reads off it and produces the notification okay so instead of depending on the state and sharing memory via that state what we do is we share memory by passing it on into a queue and that's the whole philosophy behind the channel we share memory by passing it around via channels instead of having global State essentially so here's something that we want to push so we want to essentially be able to read this as well okay and my cue is gonna be a little bit limited I'm also going to make this a task because this is going to be an asynchronous operation we're not always gonna be able to read from channel if it's gonna be empty we don't want to block the thread okay so let's go ahead and import task pushing is a synchronous operation we just push and we're it's kind of like adding an item to a list all right next thing we want to do is the writer can be finished at some point it's not really necessary or asp.net core scenario where your server is long-running but for this example since I'm in link pad and my service shouldn't be running for a long time I'm just go ahead and implement couple of functions that do actually exist on the channel but you might not need them next thing will be void complete all right or yeah let's say complete so this is where basically say right we finished writing to the channel and here we can go ahead and say oh it's complete okay and we can check is it completed or not alright so here we will say push something push something onto the queue once we're finished let's go ahead and say complete here we're gonna say wait for wait to read from a queue and when we're complete exit okay so let's go ahead and implement our channel when I wake up today I have my class channel we're going to implement implement a channel of type T right so this is the message that we're passing around the data that we're sharing between threads right or tasks even we have and I read int and I write T okay so let's go ahead and implement these interfaces all right so we get a couple of things the is complete stuff let's go ahead and just quickly sort this out we're gonna have a private pool finished right and if it's complete its void we will injustice to true and then here we just want to return finish okay so that's pretty simple let's go ahead put in the bottom so we're not troubled with that anymore yeah what we really want to solve is this push read and it's still being asynchronous so the channel sometimes acts like a queue so this is what I'm gonna implement it's essentially a channel is essentially a queue which regulates how much items you can have in a queue or who can read from a queue essentially right or where when you can read off a queue in an in an asynchronous manner so only read when we have items on there okay so we're gonna have a constructor from which we're going to initialize a queue and since we want concurrency multiple threads can be writing to this channel we want concurrent you I spell it correctly it's gonna be some generic type queue there it is and it's gonna be of type T right so again this is the message that we're passing around and this is something that we're gonna need to initialize concurrent QT there we go alright so we have our queue essentially this is where we put our messages it's just like adding stuff onto a list as soon as we add it right we finish the request and then something else can go ahead and continue here okay so when we push stuff we take our queue and we go ahead and call n queue and this is essentially we push stuff onto the queue we're gonna put the message in here okay simple enough this is a synchronous operation very safe but what we now want to do is we want to read stuff right so the way you read stuff from a queue is you try to DQ right so it's a it will return a boolean but it will also out VAR t of your result okay so if we have something let's go ahead and grab our out var message and this is going to be of type T and this is something that we can return okay and I will let this error for now because this is going to be asynchronous in a second because this is the whole point is to try to make it asynchronous something is gonna try to keep reading from this okay so there's gonna be two tasks there is going to be a producer and a consumer okay the producer is gonna put stuff and the consumer is gonna read stuff okay so when the consumer is waiting to read we don't want the consumer to block the thread so this is why this has to be synchronous okay and this is why you need to know about the semaphore this is how we're gonna solve this problem this is where we essentially say only so many items are on the queue and this is when you can read okay so it's essentially our gate right if once we push an item we want to basically say right you're allowed to read right come in and read or our messages will essentially be coming in and out all right so let's go ahead and get a semaphore and we will essentially see how this works right and we'll just say flag this change to be still underscores real quick nice so a flag is a new semaphore slim and zero because when the channel is created we have no items in the queue okay every time we push it we push a message onto the queue we want to say write consumer you can come and read this message okay and understand that multiple processes there can be multiple processes or multiple consumers for this channel and as well as multiple producers for this channel that's the whole thing about channels okay so what we essentially do we put stuff onto the queue and then we say right somebody Murr come come collect this thing here what we want to do is we want to essentially look right from our flag where we're gonna write let me make this a sink so I don't get in there we want to go ahead and wait a sink right and this is what the semaphore does so we're gonna thread is gonna come in here and it's gonna leave right until there is something on the queue once there is something on the queue it's gonna go ahead resume this task it's gonna go ahead push the item up from the what's called gonna push a message from the queue and then we're gonna return null here just to be able to return something or I guess some some types of T can't be no so we just return default if this is an int it's gonna return zero and can't be no okay so this is essentially for the channel implementation right it's really simple here the Microsoft's implementation is a little bit more lower level to make it more performant let's go ahead and try to use this you okay so we're gonna spawn two tasks right we're gonna create a producer and the consumer producer the producer is gonna write to the channel right so we want an eye writer of T and we're gonna have t here have a writer and actually I'm not gonna put a generic here I'm just gonna say that I want to string since I'm gonna be passing messages around okay and what I'm gonna do is I'm gonna say four and let's say four like a hundred messages let's have the writer we're gonna go ahead push our message and I to string probably a little bit there it is so we're gonna push it and once we're done pushing we're just gonna go ahead on our writer say that we are complete and this is a task just so it can run in parallel with the consumer as well so let's go ahead and put a slight delay here right so not a big one but you will see that this is going to be a blocking operation but it's still gonna run in parallel right so we're gonna delay for a hundred milliseconds and let's go ahead and get a waiter and get result okay at the end we just want to say that this task has completed returned right so there is no real necessity for having this asynchronous as I've explained in my async/await videos that we just might want to run this in parallel okay so this is the producer let's go ahead and create a consumer and the consumer is gonna be consuming I reader or again we just want this as string right and this is again a task so we want not for but while and we want to we want to continue reading until it is complete so we'll get that is complete and while it's not complete let's go ahead and grab the message serve our message and we're gonna grab the reader and we're gonna read right and this is a task so we actually want to do something with this so let's make this asynchronous let's awake here and we're gonna go ahead and dump this message right so we're just gonna have a number and just two distinct I'm just gonna just to be able to distinguish between this number I'm gonna mark these as messages what we're then going to do is we are going to just return or no no we don't need to return anything there right one thing with this is complete the thing is we could write all the messages and be completed before we've read everything so where we have that is completed what we all want to also do here let's say and check if the queue is empty right if we're finished and the queue is empty we're actually complete right not when we're done writing so let's go ahead grab our queue and say is empty right so when we're finished and it's empty then it's time to go so we got these two tasks one is a producer one is a consumer let's go ahead and create a channel right it's going to be a channel of string right okay simple now we want to await all of our tasks where we're gonna have the producer and we're gonna pass the channel here and then we're gonna have the consumer we're gonna press the channel here as well okay that's essentially it let's go ahead and run it and see what happens okay so I'd say quite an unexpected behavior expected them to go one by one essentially but what has happened is we cooked up this task first and it's sequential so we want to do is kick off consumer first because it is actually going to free up the thread so let's go ahead put the consumer and the producer here so we're gonna first start this task and then we're gonna kick off the producer as well okay so there we are you can see here that essentially we are pushing onto the queue right onto this channel and then this consumer essentially reads off and processes processes these messages as they come nothing is stopping us from having multiple multiples of these producers right so let's go ahead and change this up a little bit we're gonna go ahead and await on this delay and we are going to make this asynchronous so there is gonna be one problem with this write complete which we're really not too bothered about in this example however in the in production you want to use special techniques to combine writing channels or reading channels right so if two are writing to one or two are reading from one you essentially you want to do something special to accommodate that okay let's go ahead and produce a few more tasks right so this is going to be four more channels so around 40 messages but you will see that there is pretty much a good amount delay and the consumer is blasting through these items okay so that's pretty much the channel and its glory you can have a bunch of producers and it consumers right so these read I mean these write the channel and the consumer reads from a channel and the primary goal is to not share this string in a global variable here data right we don't want to share this data globally like these between the two tasks we want to pass this data around between tasks okay so that's the whole premise of this so here in Visual Studio I have a small setup which I'm gonna go over a quick li there are a few components but if it shouldn't be too much for trouble if you've been using dotnet core for a bit essentially I want to demonstrate the purpose of why you want to use a channel and that concept of services being disposed after you've initiated fire yet right so what I'm adding is just an API with controllers right so mob default controller route routing with controllers I have a notification service that I'm gonna consume later I have an in-memory database with entity framework or and I have an HTTP client that I can also inject so closing that startup where again we're going to come back to it I have a simple home controller with a send action okay so let me go ahead and fire this up so I'm gonna debug this so with that running over there I'm gonna grab postman and I'm gonna just go ahead and press send and you can see it takes around six milliseconds to complete well right so it's pretty quick right now so let's say some requests are gonna take longer than the other ones right so we're gonna have something along the lines of ask delay we're gonna have 100 milliseconds there and here so let's go ahead and wait here and let's go ahead put another 200 here let's say we're doing some calls right where these two calls are essentially us trying to dispatch on a notification right and what that might involve we will see in the service in just a second but let's go ahead and run that and let's see how basically how we're gonna make that offset we're gonna do a bump in time that takes or this request and then we're gonna again dispersal and we're gonna see what the problem is with this dispersion alright so let's go ahead and run this you can see it's bumped up to 400 milliseconds and it's gonna go down after the first request right because maybe some cash or something or whatever but we're generally taking the 300 milliseconds that we have added here so let's go ahead and offset them we don't if we have ten thousand users this time is gonna stack up quickly right so we just want to go ahead and run this in a different function all right it's gonna be a fire-and-forget task something along the lines of this is gonna happen so let's go ahead and run this and here if we send we can see where we're going back to essentially seven milliseconds six milliseconds eight we are now offsetting we're starting this different task so it runs in parallel so basically we're not waiting we're basically saying right I do this thing there so what is the problem with this in favor of time I've folded this up before the tutorial just so we can quickly go over this and jump back into channels I have a service here that I've registered that's called notifications so it's in the services folder I have here a data model which is just a simple user and I have database right where I inherit from dbcontext and I just have a user's table this is an in-memory database and what this notification service does is it consumes this database and it also has the HTTP client factory so what I'm doing here is I'm doing a little seed of the user right so if the user doesn't exist this is just a safety precaution I put a user if it doesn't there so what I do is I might get some information about the users that I want to notify their emails their mobile device IDs where am I going to be sending these notifications what notifications do they have enabled do they want to see these notifications etc I want to then go ahead and create a client I want to be able to send that notification I want to be able to store what I've sent have I sent this notification where have I sent it and I want to save it to the database right so sending a notification is not as simple as just I send notification sending notification involves by wide variety of different notification settings which notifications are you allowed to see which were clients do you have enabled for notification is it a browser is it an app is it a what's called as an email etc right so it's an involved process and let's say that this might take a second it won't but it might okay so what I'm gonna do is I'm gonna go into my home controller is let's go ahead and I will leave this for an example we're gonna you a send a and from services I'm going to inject the notifications service right notifications and what I'm gonna do is I'm gonna grab notifications and I'm gonna say send them right and because this is a task of boom I will just go ahead and say that this is a task of boolean I'm just gonna return this from that can from the controller action yeah let's go ahead and run this we'll just get a comparison of how long does this take so now back in postman I want to go to send a now I'm gonna send it and the first time it took around a second next time 88 60 80 46:44 33 37 right so you can kind of get a sense of wherever it is so let's say that this process because we're using an in-memory database quite fast and if we're gonna be using a sequel database that multiple services are gonna be talking to we're gonna be in quite of a pickle right so let's go ahead I'm hoping I'm gonna copy this function it is getting a little bit probably apologize right oh let's go ahead and add a send 8 again we're gonna line this up and what we're going to do is yeah let's first try to wrap it in a try-catch so we can see the error clearly we're gonna catch exception import this beep and just so I can see it let's go ahead and sign it here and I'm gonna put a breakpoint here okay what I'm gonna do is I'm gonna do the same thing I'm just gonna go ahead put in a test cut run in hopes to reduce the time that this service is taking okay like that okay one thing that has happened here is that this lambda is not asynchronous so we can make anything and we don't really have to wait for this service don't have an asynchronous operation here anymore so let's go ahead change this to boolean and it written is true there ok so again this is a synchronous operation we create a task that should complete some time later and then we exit the function we will then exit the action will exit the controller and what's gonna happen is we're no longer gonna have access to these services and when this task is gonna execute and break ok so again let's go ahead and probably should named it send beep yeah sent B will be calling let's say this is sent B will be calling send a on send a right hello miscommunication right this is no longer task forge is gonna be returning a boolean here I'm gonna be calling send a again and we should be able to observe the error that I was talking about hey let's go to post man let's go ahead kick this off and here we are at the exception right so what what does ever say I'll go ahead and we where's my magnifying glass buddy there it is okay okay my access disposed object a common cause of this error is disposing a context that was a result from dependency injection and then later trying to do the same context answers elsewhere in your application yeah so yeah basically this does not retain the state of this service and this is what I was caught was talking about at the beginning when I was explaining with the little basically I don't forget ask is that these services that we result here they're no longer available to this task because we actually finished exiting the scope okay so this is the problem with this fire-and-forget solution and as well as we're basically creating a stack of tasks that might over time take over our process and starve other threads aim so let's close everything and let's think about how can we offsets right we essentially want to have this notification service as a producer or notification okay and then we have a consumer as a dispatcher of notification okay so we will have to have a process that is sort of trying to read off a channel and this is somewhere you can use a hosted service or a background service right so this is where we're gonna go into services and we are going to add a hosted service okay I understand at this point maybe if you're wondering where the heck of the channels we haven't seen the implementation of the channels it's more important to understand what problem the channels solve law rather than the channel itself because the channel is dead simple it has a couple of functions that are really easy to figure out you just need to know where to put the channel in the bigger picture based hang in there so a hosted service let's go ahead and create a hosted service and this is just going to run in the background of the SPF nine core application it's not going to be able to be hit by a request it's something that we can put the channel can plug the channel into it and send stuff into it and we'll process it in the background right so let's go ahead and really a terrific dispatcher right we have a notification dispatcher we are going to make this AI or rather background service right so the background service it inherits from I hosted service and then our startup and the hosted service accepts at T hosted service where T hosted service is I hosted service all right so the notification dispatcher is what we're going to put here and this is what it's basically going to start and it's gonna start looping it so let's go ahead implement the abstract class and here we have a function write execute erasing gonna start and it's gonna not gonna stop running all right so this is that consumer task so the notification dispatcher is a consumer and it's gonna try to read from the notifications channel alright oh here we want our while loop and if not complete read from channel and send notification all right real simple now we basically just have to put a pipe from the notification service and again this notification service can be something different like create order register the website etc okay sending emails getting stuff from the database writing to the database these are all basically time-consuming tasks is there is that communication Oh what we want to do is we essentially want to grab these services and just stick them in here okay oh poor HTTP Klein right I'm just copy possible I will then grab this functionality here and I'm just gonna do the Sentinel is that's essentially what needs to happen to send the net notification okay and this will have to be asynchronous and any sync will need the entity framework namespace okay so once everything compiles but let me drop down the solution Explorer and by the way they get string I'm just getting something from the Microsoft documentation so rename the constructor so we have our database we have our HTTP client factory one thing with the database we might need to get it from a service provider and this is something we'll handle if the error arises in and go ahead and usually what you would do is you would catch this whole thing right like this and you would log it let's go ahead and bring in a real logger so I logger notification dispatcher logger ok and let's create this logger field all right so we're not touching channels just yet it's getting getting all setup log error notification failed exception e let's go ahead system right so log error what allows you to do is log in an exception and then the MIS okay and then any parameters that you want to put in yeah that's essentially where we want a break point if anything does go wrong but we'd never want to essentially break this loop of the notification dispatcher okay so the channel let's go ahead and connect this channel right in the startup what I want to do is add a channel right so services add singleton and it's going to be a singleton because I want this channel to exist and it's just one channel right never disposed and we don't need the type what we want to do is we want to grab the channel right so it's a channel plus in system spreading the channels namespace there it is right and what the channels here so let's go ahead and quickly explore it real quick we have the channels class on its own and a collection of static functions which will create your channel so we have a channel of type T and it's an abstract class right so you can inherit from it it inherits from channel of T right T read right so we are gonna write a type we're going to read a type and the standard channel that we are getting here as type and type out right so going into this channel we have the reader we have the writer a same situation and the primary theme the really little subtle differences are just in the functions options that these functions provide you the completion tasks just how it works but all the concepts of read is a done and are there and the same thing for the I can get there or the channel writer market complete or try to write to it right and I will quickly glance over these functions once we get sort of writing this but playing around with them should give you a good idea what they are right I just want to get over the real-world example of where to use channel hey so what we want to do is because we're gonna be passing around a string I'm just gonna go ahead and create an unbounded channel which means much as as much as much messages as one can go on this Q well the channel is if you will have a lack of memory which is rarely the case these days you want to put a limit on your Q and then you're not gonna get a memory overflow exception or whatever so create unbounded channel of type string this is gonna return us a channel of type right so here you can see the type channel of string and this is no service this is now a singleton service that we can inject okay and there are other other inks that you can obvious object-oriented inks you can use you can wrap it you can basically create this channel and put implementations of the reader and writer and then Jack reader and writer separately different services but here what we're going to do is let's go ahead and just inject this channel into an action and then into the dispatcher and make the action communicate with the dispatcher hey let's go ahead and grab our home controller here at the bottom what I'm gonna do is I'm going to create a public Bull ascend a CC per channel and from services we're gonna go ahead and grab a channel of type string because that's what we have injected and let's go ahead grab this channel we're gonna need the name space let's go ahead and return bulk bulk a troop right here and what I'm gonna do is I'm gonna grab a task off Bowl because this is going to need this will need to be asynchronous because our channel is just quickly going over we're gonna be using the writer because we're going to be writing to the channel and we the complete function we mark it as complete nothing is going to be written to this channel ever again basically we then have tri complete is gonna throw an exception if it can't complete it right with the exception that you supplied try right and then wait to write a same kind of work and in hand because try write a synchronous and wait to write a sing kind of lets you know when you can write okay so this is primarily more if you have a bounded channel okay you sort of you wait for it to write e sync and then you try to write you think if you are unsuccessful you very wait to write a sync again okay if you choose to write a sync you essentially combine the try right and way to write a sync when you can write you will write okay so that's pretty much what we're gonna use let's go ahead and just say hello right simple message let's go and wait on this okay and then we're gonna return so we have a service and what the main thing to understand is that we're trying to achieve this result of offsetting work and if you scroll back to the video remember the numbers it was somewhere around 30 30 40 milliseconds that we get a result with this whole shebang so this is what we're trying to be we're trying to beat the 30 40 we're gonna try to go back to the six and seven milliseconds that we were getting from the beginning okay so my own channel let's go ahead and service it in our notification dispatcher and a couple of thing with these services is this database is actually gonna break so just because this is a singleton and the database is a scope I guess it's just about dependency injection and lifetimes we're gonna fix that let's first take care of the channel right while we are on the flow of the channels rubber channel initialize the field so if not complete how do you use this reader right where this is a consumer we're gonna be using the reader we're reading from the channel channel consumer is reading producer writing name-o completion it will return a task which we just have to base if it is a complete dude this task completed if not keep looping okay then let's leave the comments we want to grab the message let's grab the channel we will go to the reader right and the kind of the same scenario whereas with the functions on the writer it's more or less the same thing we either want to read or write right but it's just the options that they provide right so read all these think do you want to read all the messages or rebasing just one message do you want to do a synchronous try read and wait to read a sink which although these are kind of comprised into a read async so you try to read you're in successful you wait wait to read async and once you're ready to read you try to read all right unsuccessful you're back to wait here you're basically you're ready to read you read alright that's what we're gonna use let's go ahead and read the message again this is asynchronous we'll need to wait on this and now let's sort this database provider right basically it's gonna crash because it's it's a scope and the notification dispatcher is a single right repeating myself here what we want in is an eye service provider so let's grab the provider and let's create a field here and where we're using this database we want to grab a using statement and we want to create a scope from our provider right and once the scope ends we want to dispose it be provider so database equals yeah we want to get the service brighter get required scope and we're gonna grab our database that we inject it and yeah essentially we're either message we're not consuming it really but if we need to we can let's go ahead and put a breakpoint here so we reach an exception we can no let's go ahead and also put a breakpoint here so we know at which point we sort of start reading or start are starting to wait to read and usually this is gonna get hit at the application start and then the thread is gonna go do something else right because this background services started as soon as server starts again so recap before we go we add a singleton Channel so this is just a channel that exists somewhere in memory and then we got a bunch of services that we inject into our notification dispatcher which is going to read from this channel and it's gonna do its thing right it doesn't matter what it does it's all about reading we then are gonna trigger the rights to the channel by by calling controller action where we can inject our Channel and just to note and inject this channel anywhere we want the notification service we can inject it in there if we want we're just gonna opt in for the controller action okay oh let's go ahead and run this let's see what happens so here we hit the first breakpoint as soon as the application start you can see we're having actually gotten our home page yet I don't think we've actually hit the home page or there is no home page even so nevermind let's go ahead and just f5 here this will return the thread and when the application can work as once to write so what we want to do now is we want to send a request to home send see so we send it okay and here we're entering this scope so I will remove this breakpoint now just just so you know as soon as we push stuff onto the queue it kind of starts executing in the background right we're gonna resume and here basically we loop back and we start to wait to read from the channel again the service has come back it is it long because I've waited on the breakpoint but we'll see this run full speed in just a second right and then we are basically waiting again once I resumed the thread has given up control here I'm gonna remove the breakpoint here and that you see we haven't had any exception so everything is working as expected what I'm gonna do now is in the home controller there are no breakpoints here what I want to do is I just want to spam some sense all right so I'm gonna send 40 milliseconds send again 1024 nine seven so you can see we are getting the offset of the workload and we're back at sort of snappy execution right and again I think we can go back to send be to sort of get a comparison so send me 64 59 46 47 3362 36 33 like some kind of sportscaster but you can see that with the dispatcher with the channel we can basically we can have a separate we can have the main task and we basically off load we separate one task here and one Tasker here so now we have two tasks running and the notification dispatcher is this background task and the way we connect them is this channel all right and whenever something puts something in the channel the dispatcher is gonna read it and process it right and the channel has its own lifetime sorry the dispatcher the consumer has its own lifetime it has its own services injected and it manages its own State and all you are doing is passing the messages around right so yeah this is pretty much a real-world use of channels in a single application another big really big way that channels are used in the industry is the means of a separation of concerns so you have distributed system you have micro services the way you communicate between micro services is through channel services so you will have one service put a message on the channel service in the cloud and then some other box you will have a cluster so you'll have many boxes one of them will read from a channel basically if too many items start accumulating on the channel you spin up more boxes and that basically horizontal scaling it if you're not fast enough processing requests you get more more via virtual machines it's an and that's pretty much where channels can be used as well in distributed computing it's quite an important concept you know yeah this will be it for this episode all the code is available in the link in the description if you have any questions comment enjoyed this video leave a like subscribe don't forget to join my discord server I also stream on Sundays and Wednesdays so make sure you tune in for that hopefully I'll see you in my other videos
Info
Channel: Raw Coding
Views: 15,217
Rating: 4.9464626 out of 5
Keywords: c#, asp.net core, middleware, tutorial, c# tutorial, asp.net core tutorial, channels, explained, real world, problem, System.Threading.Channels, channels in c#, how do channels work, how to use channels?, example
Id: E0Ld7ZgE4oY
Channel Id: undefined
Length: 47min 11sec (2831 seconds)
Published: Sun Apr 26 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.