tag:blogger.com,1999:blog-2889416825250254881.post3600738132793992252..comments2024-01-27T11:41:32.146+00:00Comments on Byte Rot: Server-side Async: Careful with that Axe, Eugenealiostadhttp://www.blogger.com/profile/05695786967974402749noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-2889416825250254881.post-81845116350352572542016-10-04T09:20:17.828+01:002016-10-04T09:20:17.828+01:00Did you know that you can generate money by lockin...Did you know that you can generate <b>money</b> by locking <b>premium pages</b> of your blog / website?<br />Simply join <b><a href="http://syntaxlinks.com/affiliate-network-reviews/network/15/AdWork-Media/" rel="nofollow">AdWorkMedia</a></b> and <b>use their Content Locking widget</b>.Bloggerhttps://www.blogger.com/profile/07287821785570247118noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-31442092746283675312012-10-03T18:43:21.932+01:002012-10-03T18:43:21.932+01:00Thanks Lasse for correcting me. I was misguided by...Thanks Lasse for correcting me. I was misguided by a podcast. I will go back to it, it could be just my misunderstanding.<br /><br />aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-28637339565899296132012-10-03T09:46:55.029+01:002012-10-03T09:46:55.029+01:00Task.Run does not create a new Thread, in fact it&...Task.Run does not create a new Thread, in fact it's just a shortcut of Task.Factory.StartNew(), calling the same logic with some default parameters. See http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspxAnonymoushttps://www.blogger.com/profile/12668997714803289776noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-38969289924789176702012-09-24T21:58:16.554+01:002012-09-24T21:58:16.554+01:00Thanks. I think I have again learnt one bit more a...Thanks. I think I have again learnt one bit more about async. Now I need to explain why even in load testing, thread-based async (even CPU-bound) works better than sync :(aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-48100234213579617522012-09-22T17:26:13.423+01:002012-09-22T17:26:13.423+01:00I was actually looking at it using Reflector and a...I was actually looking at it using Reflector and as soon as found it your answer arrived.<br /><br />I think now I can see where you are coming from! Also that link was useful. As I said in the post, as soon as I think I get async, something happens and my whole understanding gets upside down!<br /><br />Thanks anyway, let me digest the stuff. aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-22952437776893497872012-09-22T17:13:09.044+01:002012-09-22T17:13:09.044+01:00No, absolutely not!
If you decompile down the Sys...No, absolutely not!<br /><br />If you decompile down the System.Data.dll, you will actually see what it does but basically, it creates a Task over the old-school APM methods through Task.Factory.FromAsync.<br /><br />Have a look: http://stackoverflow.com/questions/5018897/tpl-taskfactory-fromasync-vs-tasks-with-blocking-methods<br /><br />My view is this: don't ever use Task.Factory.StartNew on a server application unless it's meant to be used by small amount of users and a low level traffic is expected (such as a Back Office application, etc).Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-25195994865762156322012-09-22T16:59:42.410+01:002012-09-22T16:59:42.410+01:00So what does ExecuteReaderAsync do? Is it not the ...So what does ExecuteReaderAsync do? Is it not the case that it will use Task.Factory.StartNew?aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-59027556098537866602012-09-22T16:57:28.980+01:002012-09-22T16:57:28.980+01:00Here is an example:
public async Task> GetAsyn...Here is an example:<br /><br />public async Task> GetAsync() {<br /><br /> using (var conn = new SqlConnection(_connectionString)) {<br /> using (var cmd = new SqlCommand()) {<br /><br /> cmd.Connection = conn;<br /> cmd.CommandText = _spName;<br /> cmd.CommandType = CommandType.StoredProcedure;<br /><br /> conn.Open();<br /><br /> using (var reader = await cmd.ExecuteReaderAsync()) {<br /> <br /> return reader.Select(r => carBuilder(r)).ToList();<br /> }<br /> }<br /> }<br />}<br /><br />private Car carBuilder(SqlDataReader reader) {<br /><br /> return new Car {<br /><br /> Id = int.Parse(reader["Id"].ToString()),<br /> Make = reader["Make"] is DBNull ? null : reader["Make"].ToString(),<br /> Model = reader["Model"] is DBNull ? null : reader["Model"].ToString(),<br /> Year = int.Parse(reader["Year"].ToString()),<br /> Price = float.Parse(reader["Price"].ToString()),<br /> };<br />}<br /><br />As you can see, we are using cmd.ExecuteReaderAsync instead of cmd.ExecuteReader. When we await on cmd.ExecuteReaderAsync, we will suspend the logical execution flow of the code and the thread will go back to thread pool instead of hanging there doing nothing. Also, we are using await inside a using statement here. It's completely legit and compiler will handle that. So, compiler will ensure that reader won't be disposed before we are done with it.<br /><br />(BTW, There are a few more settings to enable asycn database calls, you can check them out here: http://www.tugberkugurlu.com/archive/asynchronous-database-calls-with-task-based-asynchronous-programming-model-tap-in-asp-net-mvc-4)<br /><br />Now assume that we will do this with cmd.ExecuteReader and have a sync method instead. Then, we will wrap this inside Task.Factory.StartNew. We will free up the main thread when we await on Task.Factory.StartNew but we will block a thread pool thread this time. + we will generate an unnecessary thread hoop which is vital for a server app.Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-13860152108430712542012-09-22T16:37:59.190+01:002012-09-22T16:37:59.190+01:00OK, so let's imagine we call _carRepository.Ge...OK, so let's imagine we call _carRepository.GetAsync(id) returning Task instead of Get() so can you tell me what implementation look like that would use IO completion port?<br /><br />As I said before "Let's assume repository work is IO-bound so there is benefit in async." So even _carRepository.Get(id) is UI-bound but that is not async.aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-63085248938285094152012-09-22T15:26:29.823+01:002012-09-22T15:26:29.823+01:00"In fact Lucian from Microsoft here believes ..."In fact Lucian from Microsoft here believes there is no point in doing async in ASP.NET" <br /><br />What Lucian talks about is similar to what I have been trying to express. He expressed that he doesn't think of any use cases for "Multithreading" inside ASP.NET apps (the words are not the same here as his). The talk from 16 min to 24 min is just expressing what I meant.<br /><br />Just after that he expressed that I/O bound async is useful (again, not the same words but meaning is similar).Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-76681785603009822682012-09-22T14:49:34.001+01:002012-09-22T14:49:34.001+01:00Ah, I went to http://www.dotnetrocks.com/default.a...Ah, I went to http://www.dotnetrocks.com/default.aspx?showNum=78 instead of http://www.dotnetrocks.com/default.aspx?showNum=785 :) I'll listen to that.<br /><br />Ask the question on SO, man. Maybe I am wrong (which I don't think but who knows).Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-75465990998806222712012-09-22T14:44:44.687+01:002012-09-22T14:44:44.687+01:00I listened to that one as soon as it came out. See...I listened to that one as soon as it came out. See my comments!<br /><br />And also the other one is from July 2012. Where did you get 2004 from?!aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-27490688550250990522012-09-22T14:35:51.004+01:002012-09-22T14:35:51.004+01:00Wow, that podcast is way too old :) August 30, 200...Wow, that podcast is way too old :) August 30, 2004. Here is a new one for ya:<br /><br />http://hanselminutes.com/327/everything-net-programmers-know-about-asynchronous-programming-is-wrongTugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-55764406540299092642012-09-22T14:33:47.909+01:002012-09-22T14:33:47.909+01:00"You say _carRepository.Get(id) is not async...."You say _carRepository.Get(id) is not async. Yes, it is not but we have made it so by running the task."<br /><br />You are not making it async. The thread which will execute that code will not be freed up because the method is not benefiting from the async I/O Completion Ports on Windows. Yes, you will free up the main thread here but you will still block a thread pool thread (assuming you are using the default TaskSchaduler).<br /><br />What you do here is multithreading and this is going hurt your performance if you have lots of traffic. If I were your, I would repro my issue and ask someone from the team about that (probably ask on stackoverflow?).Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-88699321274441818732012-09-22T11:30:26.991+01:002012-09-22T11:30:26.991+01:00I am sorry, you have completely lost me. Perhaps I...I am sorry, you have completely lost me. Perhaps I just do not get Async.<br /><br />Let's assume repository work is IO-bound so there is benefit in async. You say _carRepository.Get(id) is not async. Yes, it is not but we have made it so by running the task. That task must be created somewhere, either in controller or repository itself, right? Guess what, that would take up a thread regardless and it will be from the SAME threadpool. So moving the task creation outside of controller does not make any difference. <br /><br />Now we know that ASP.NET and our code share the same ThreadPool. So any benefit we get could be limited since we could be hijacking ASP.NET threads if throughput is high. But if throughput is high, we are stuffed regardless, resources are limited!<br /><br />In fact Lucian from Microsoft here believes there is no point in doing async in ASP.NET: http://www.dotnetrocks.com/default.aspx?showNum=785 <br />aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-77144955539069245832012-09-21T23:24:54.294+01:002012-09-21T23:24:54.294+01:00It's certainly going to kill your perf if you ...It's certainly going to kill your perf if you use the below method:<br /><br />// async version (on another controller)<br />public Task GetAsync(int id)<br />{<br /> return Task.Factory.StartNew(() => _carRepository.Get(id));<br />}<br /><br />_carRepository.Get method is not an asynchronous method. So, you are not going to free up thread here. Instead, you will consume one more unnecessary thread to handle the request. In other words, this is multithreading, not async operation.<br /><br />Assuming that your ASP.NET request is handled by thread #1 and _carRepository.Get method is handled by thread #2; The thread #2 will wait till the _carRepository.Get operation completes and u will be blocking a thread pool thread instead of the main thread but u will be blocking a thread at the end of the day.<br /><br />If this was a client application such as a WPF or a WinRT app, your scenario would work fine because ur main concern will be to free up the UI thread. In a server application, every thread has its own cost.<br /><br />If this was an asynchronous operation instead of a multithreaded operation, the thread #2 would go back to the thread pool and would be ready to process any other work. Finally, when the async operation is done, a thread would be drawn from the thread pool to process the request (assuming you are using the Default TaskSchaduler).Tugberkhttps://www.blogger.com/profile/01145356632785594598noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-83440460612143953052012-09-21T14:21:00.419+01:002012-09-21T14:21:00.419+01:00I am not sure what you are up to - does not make s...I am not sure what you are up to - does not make sense to me. At the end of the day, you will be using a thread from somewhere anyway. But the thread that is handling request can go back and serve another request. There is no alternative, is there? <br /><br />Anyway, Task.Factory.StartNew is just a syntactic sugar.aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-5796920456416385042012-09-21T00:38:13.101+01:002012-09-21T00:38:13.101+01:00Yes, u are taking a thread from the thread pool wi...Yes, u are taking a thread from the thread pool with StartNew but u are blocking that thread this time and u are also generating a unnecessary thread hoop. The whole idea behind the asyn is to free up the thread. If carRepo.Get() take e seconds, ur thread will do nothing but waiting till the job is done. Just to be on the safe side, I would ask someone form the team for that (levi, damian, brad, etc) tugberkhttps://www.blogger.com/profile/07851236878660995805noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-61661030086531943762012-09-20T23:53:35.469+01:002012-09-20T23:53:35.469+01:00Well I think you are probably mixing this with Tas...Well I think you are probably mixing this with Task.Run which creates a dedicated thread. Task.Factory.StartNew according to MSDN is equivalent to using constructor and then calling start (http://msdn.microsoft.com/en-us/library/dd321439.aspx):<br /><br />"Calling StartNew is functionally equivalent to creating a Task using one of its constructors and then calling Start to schedule it for execution. However, unless creation and scheduling must be separated, StartNew is the recommended approach for both simplicity and performance."<br /><br />On the other hand, Task.Run creates a new Thread instead of using the ThreadPool hence is not recommended unless really a dedicated thread is required.aliostadhttps://www.blogger.com/profile/05695786967974402749noreply@blogger.comtag:blogger.com,1999:blog-2889416825250254881.post-17013538815563883292012-09-20T22:46:56.000+01:002012-09-20T22:46:56.000+01:00// async version (on another controller)
public Ta...// async version (on another controller)<br />public Task GetAsync(int id)<br />{<br /> return Task.Factory.StartNew(() => _carRepository.Get(id));<br />}<br /><br />While I am not completely sure, the above method will decrease your web app's performance if you have high traffic because your will generate a lots of thread hoops. Task.Factory.StartNew is just a fancy way of saying Thread.Start. The reason for that is that it is not an asynchronous method. What you are doing here is multithreatening. I might be totally off-base here because u might be using this only for demo purposes (it is midnight here, spare me :)).<br /><br />I have been doing that a lot till bunch people punched me in the face :) http://stackoverflow.com/questions/8743067/do-asynchronous-operations-in-asp-net-mvc-use-a-thread-from-threadpool-on-net-4tugberkhttps://www.blogger.com/profile/07851236878660995805noreply@blogger.com