How are IIS7 threads assigned? - c#

I added log4net to my application and can now see the thread Ids of user activities as they navigate through my website. Is there any specific algorithm to how threads assignment happens with IIS7, or is it just a random number assignment (I suspect it's not completely random because my low traffic site show threads mostly in the range 10-30)? Any maximum to the number of threads available? And I notice that my scheduler shows up with a weird threads id -- any reason for this? The scheduler is Quartz.net and the id shows as "Scheduler_Worker-10", and not just a number.

This explains all you need to know.
An Excerpt:
When ASP.NET is hosted on IIS 7.0 in
integrated mode, the use of threads is
a bit different. First of all, the
application-level queues are no more.
Their performance was always really
bad, there was no hope in fixing this,
and so we got rid of them. But perhaps
the biggest difference is that in IIS
6.0, or ISAPI mode, ASP.NET restricts the number of threads concurrently
executing requests, but in IIS 7.0
integrated mode, ASP.NET restricts the
number of concurrently executing
requests. The difference only matters
when the requests are asynchronous
(the request either has an
asynchronous handler or a module in
the pipeline completes
asynchronously). Obviously if the
reqeusts are synchronous, then the
number of concurrently executing
requests is the same as the number of
threads concurrently executing
requests, but if the requests are
asynchronous then these two numbers
can be quite different as you could
have far more reqeusts than threads.
So basically, if requests are synchronous, the same number of threads per request. See here for various parameters.

I've explained this is a blog post on my blog
ASP.NET Performance-Instantiating Business Layers
The title doesn't coincide with your question but I explain the way IIS handles Requests and I believe you'll have your answer.
A quote from the article
When IIS fields a request for your
application it hands it over to the
worker process. The worker process in
turn creates and instance of your
Global class (which is of type
HttpApplication). From that point on
the typical flow of an ASP.NET
application takes place (the ASP.NET
pipeline). However, what you need to
know and understand is that the worker
process (think of it as IIS really)
keeps the instance of your
HttpApplication (an instance of your
Global class) alive, in order to field
other requests. In fact it by default
it would create and cache up to 10
instances of your Global class, if
required (Lazy instantiation)
depending on load the number of
requests your website receives other
factors. In Figure1 above the
instances of your ASP.NET application
are shown as the red boxes. There
could be up to 10 of these cached by
the worker process. These are really
threads that the worker process has
created and cached and each thread has
its own instance of your Global class.
Note that each of these threads is in
the same App Domain. So any static
classes you may have in your
application are shared across each of
these threads or application
instances.
I suggest you read that article and I'll be happy to answer any questions you may have. Please note that I've intentional kept the article simple in that I don't talk about what happens in the kernel or go into details of the various components that participate. Keeping it simple helps people understand the concepts a lot better (I feel).
I'll answer some of your other questions here:
Is there any specific algorithm to how threads assignment happens with IIS7?
No, for all intents an purposes it's random. This is explain in the article I pointed to. The short answer is that if a cached thread is available then IIs will use it. If not, it will create a new thread, create and instance of your HttpApplication (Global) and assign all of the context to it. So in a site that's not busy, you may see the same threads handle requests. But there are no guarantees. If there is more than one free thread IIS will pick a thread at random to service that request. You should note here, that even in a not so busy site, if your requests take a long time, IIS will be forced to create new threads to service other incoming requests.
Any maximum to the number of threads available?
Yes (as explained in th article) typically 10 threads per worker process. This can be adjusted but I've worked on a number of extremely busy websites and I've never had to. The key is to make your applications respond as fast as possible. Mind you an application can have multiple worker process assigned to it (configured in your app pool) so in busy sites you actually want multiple worker processes for your application, however the implication is that you have the required hardware (CPU cores and memory).
The scheduler is Quartz.net and the id shows as "Scheduler_Worker-10", and not just a number
Threads can have names instead of Ids. If the thread has been assigned a name then you'll see that instead of an id. Of course for threads IIS creates you have no such control. Mind you, I've not used (nor know about Quartz) so I don't know about that but I'm guess that's the case.

Related

Limiting threads per Class

I have a .NET web application, which for each request sends requests to one of the api from a set of multiple API's (which api to hit depends on the request type), gets the response, processes it and returns the response.
Suppose at any given point of time, lets say we have a maximum of 100 threads, and we get 100 requests (lets assume each thread is handling one request each) for which the request needs to go to API-1 and suddenly API-1's response time increases, and then we get subsequent requests which need to go to API-2,3 ... n and all these API(s) are working perfectly.Requests for these API(s) won't be served until one the threads get free from processing API-1 which results in an overall performance impact of the .NET web application.
What I want to achieve is that I want to limit the number of threads for each API (lets say we have a class for each api having some methods) such that each class does not exceed the maximum number of threads allocated to it.
(If I have n classes and 100 threads , I should be able to divide them into thread pools of 100/n each)
I tried a few links for thread pools but couldn't achieve the same I wanted.
Probably your application is a good target for a asynchronous programming model which, if used correctly, eliminates the blocked threads downtime issue.
Asynchronous programming in C# is a very broad topic that has been discussed a lot. Check following resources:
What is the difference between asynchronous programming and multithreading? discussion on StackOverflow
Asynchronous programming page on Microsoft Docs
Async and Await article by Stephen Cleary and his blog in general
What do the terms “CPU bound” and “I/O bound” mean? discussion on StackOverflow
If you really need to, you can still limit number of ThreadPool threads (workers) as usual. See Using TPL how do I set a max threadpool size discussion on StackOverflow.

Thread IIS wont start C#

Before I go into this question, I d like to say that, I have read the threading modeling for IIS 7, 7, 7.5 so I know how threads are handled.
My application starts a thread when a request comes in.
We can assume the threads as cron jobs.
GET request comes in, Lets say /Handle
in the scope of /Handle I start a thread from that action , THREAD A
I am not long polling the GET request, so it returns back to the
user right away. So thread handling the GET is returned to the POOL
Then I wait until the thread A completes to do anything else.
So No threads are running as far as I know. Both the thread that was
handling the GET and THREAD A has exited.
I make the same request a few times SEQUANTIALLY. I always wait for both threads to exit.
After a while `Thread.Start()1 function blocks.
Questions :
I know that the threads are returning and I am not leaking any ghost threads.
Why does IIS not allowing me to start new threads after a like 4-5 requests. ?
What is the right way to create application thread for the user application.
If I said Thread t= new Thread(), does this allocate a thread from the pool that handled the GETS or CLR?
I am using IIS7.
I know that I exit each thread, I call a JOIN on THREAD A , and it never blocks, and at this point I am not worried about scalability so I always have ONE user hitting the server sequentially.
So to answer your question "What is the right way to create application thread for the user application?" (i.e. ASP.NET application) - You have many options:
run on the ASP.NET thread, without any threading - ASP.NET will still handle more then one request
use async calls (see async operations) for long running operations
use CLR ThreadPool
send a message to some other server (e.g. using WCF services), so the long running processing takes place outside the Web server.
You mentioned reading about threading in ASP.NET, but in "MSDN: Performing Asynchronous Work, or Tasks, in ASP.NET Applications" there's a relatively short description of how threading in ASP.NET works. At the end of the post, there's a question:
"Q4: Should I create my own threads (new Thread)?" and the answer for that question is "A4) Please don’t (create new Threads). Or to put it a different way, no!!! (...) ".
And to answer your question: "Why does IIS not allowing me to start new threads after a like 4-5 requests"?
That's really a strange behaviour, maybe IIS knows that your are doing it wrong ;)

Setting a low thread priority for a heavy load task

First, thanks for all the replies!
I want to be more specific - I have a website that shows some current and historical reports. I want to be able to allow users to delete all or some of the history, while still navigating the website.
Therefore, I want to run a separate thread that will handle deleting the data, but I want to give this thread a low priority so it doesn't make the web site slow or unresponsive.
I'm in the design phase right now and I'd appreciate some strategy suggestions. Thanks!
You should be fine. Lowering the priority of CPU-intensive background tasks to allow 'normal' response from a GUI and/or other apps is one of the better uses for altering thread priorities.
Note that lowering the thread priority is not going to have an enormous efect on any resource except CPU, but still worth doing IME.
If you want to carry on using Firefox, Office, VLC etc. while running your app then, yes, lower the priority of the CPU-heavy threads. You should then be able to browse SO, listen to some albums or watch a few films while waiting for your results to eventually come out :)
Note that if you want to change the priority for a thread, you should make sure it's one you've created yourself. It's not good to change the priority on a thread pool thread. This means avoiding the new Task features, unless you're prepared to write a TaskScheduler that doesn't use the thread pool.
Also consider setting the process priority instead, if that suits your scenario. See MSDN for more info. This would affect threads equally.
Edit: Thanks for the additional information. It sounds as though your code is hosted in IIS. From this answer we can confirm that IIS uses the same thread pool as ThreadPool.QueueUserWorkItem - the standard .NET thread pool. Therefore you must not alter the priority of a thread pool thread; these threads belong to IIS.
You could create your own thread. But it seems ill advised to try to host a background operation in IIS like this. You never know when the app pool might be recycled, for example.
It would be better to consider a couple of other options. The best solution for a potentially long running background operation seems to be workflow services. Used in conjunction with AppFabric Server, these are very powerful and sound as though they would handle your situation.
A simpler alternative would be to move the process outside of IIS. Maybe the user's action could mark items for deletion, then a scheduled task outside of IIS could run to perform the slow operation.
I would use ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(MyDeleteMethod), itemsTobeDeleted)
In MyDeleteMethod, you may consider breaking the deletion process in different bulks. In other words, you can specify a max number of rows to be deleted every time you are running the delete method.
If you are worried about number of available connections in the db pool, you can improve the performance by defining a static object (with a timer) and add the itemsTobeDeleted to that list(you need to use lock for sync access). Whenever timer Elapsed event fires, you can perform the bulk delete ( For instance you have 5,000 record and you are going to delete them 500 by 500 ).

ThreadPool.QueueUserWorkItem uses ASP.Net

In Asp.Net for creating a huge pdf report iam using "ThreadPool.QueueUserWorkItem", My requirement is report has to be created asynchronously , and i do not want to wait for the Response. I plan to achieve it through below code
protected void Button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(report => CreateReport());
}
public void CreateReport()
{
//This method will take 30 seconds to finish it work
}
My question is ThreadPool.QueueUserWorkItem will create a new thread from Asp.Net worker process or some system thread. Is this a good approach ?, I may have 100 of concurrent users accessing the web page.
The QueueUserWorkItem() method utilizes the process's ThreadPool which automatically manages a number of worker-threads. These threads are assigned a task, run them to completion, then are returned to the ThreadPool for reuse.
Since this is hosted in ASP.NET the ThreadPool will belong to the ASP.NET process.
The ThreadPool is a very good candidate for this type of work; as the alternative of spinning up a dedicated thread is relatively expensive. However, you should consider the following limitations of the ThreadPool as well:
The ThreadPool is used by other aspects of .NET, and provides a limited number of threads. If you overuse it there is the possibility your tasks will be blocked waiting for others to complete. This is especially a concern in terms of scalability--however it shouldn't dissuade you from using the ThreadPool unless you have reason to believe it will be a bottleneck.
The ThreadPool tasks must be carefully managed to ensure they are returned for reuse. Unhandled exceptions or returns from a background thread will essentially "leak" that thread and prevent it from being reused. In these scenarios the ThreadPool may effectively lose it's threads and cause a serious slowdown or halt of the process.
The tasks you assign to the ThreadPool should be short-lived. If your processing is intensive then it's a better idea to provide it with a dedicated thread.
All these topics relate to the simple concept that the ThreadPool is intended for small tasks, and for it's threads to provide a cost-saving to the consuming code by being reused. Your scenario sounds like a reasonable case for using the ThreadPool--however you will want to carefully code around it, and ensure you run realistic load-tests to determine if it is the best approach.
The thread pool will manage the number of active threads as needed. Once a thread is done with a task it continues on the next queued task. Using the thread pool is normally a good way to handle background processing.
When running in an ASP.NET application there are a couple of things to be aware of:
ASP.NET applications can be recycled for various reasons. When this happens all queued work items are lost.
There is no simple way to signal back to the client web browser that the operation completed.
A better approach in your case might be to have a WCF service with a REST/JSON binding that is called by AJAX code on the client web page for doing the heavy work. This would give you the possibility to report process and results back to the user.
In addition to what Anders Abel has already laid out, which I agree with entirely, you should consider that ASP.NET also uses the thread pool to respond to requests, so if you have long running work like this using up a thread pool thread, it is technically stealing from the resources which ASP.NET is able to use to fulfill other requests anyway.
If you were to ask me how best to architect it I would say you dispatch the work to a WCF service using one way messaging over the MSMQ transport. That way it is fast to dispatch, resilient to failure and processing of the requests on the WCF side can be more tightly controlled because the messages will just sit on the queue waiting to be processed. So if your server can only create 10 PDFs at a time you would just set the maxConcurrentCalls for the WCF service to 10 and it will only pull a maximum of 10 messages off the queue at once. Also, if your service shuts down, when it starts up it will just begin processing again.

Are there any non-obvious dangers in using threads in ASP.NET?

This is something of a sibling question to this programmers question.
Briefly, we're looking at pushing some work that's been piggy-backing on user requests into the background "properly." The linked question has given me plenty of ideas should we go the service route, but hasn't really provided any convincing arguments as to why, exactly, we should.
I will admit that, to me, the ability to do the moral equivalent of
WorkQueue.Push(delegate(object context) { ... });
is really compelling, so if its just a little difficult (rather than inherently unworkable) I'm inclined to go with the background thread approach.
So, the problems with background threads I'm aware of (in the context of an AppPool):
They can die at any time due to the AppPool being recycled
Solution: track when a task is being executed, so it can be re-run* should a new thread be needed
The ThreadPool is used to respond to incoming HTTP queries, so using it can starve IIS
Solution: build our own thread pool, capping the number of threads as well.
My question is, what am I missing, if anything? What else can go wrongǂ with background threads in ASP.NET?
* The task in questions are already safe to re-run, so this isn't a problem.
ǂ Assume we're not doing anything really dumb, like throwing exceptions in background threads.
I would stay away from launching threads from with-in your IIS AppDomain for StackOverflow. I don't have any hard evidence to support what I am going to say, but working with IIS for 10 years, I know that it works best when it is the only game in town.
There is also an alternative, I know this is going to be sort of a take off on my answer over on the programmers thread. But as I understand it you already have a solution that works by piggy-backing the work on user requests. Why not use that code, but only launch it when a special internal API is called. Then use Task Scheduler to call a CURL command that calls that API every 30 seconds or so to launch the tasks. This way you are letting IIS handle the threading and your code is handling something that it already does easily.
One danger I ran into personally is the CallContext. We were using the CallContext to set user identity data, because the same code was shared across our web application and our .NET Remoting based application services (which is designed to use the CallContext for storing call specific data) - so we weren't using the HttpContext.
We noticed that, sometimes, a new request would end up with a non-null identity in the CallContext. In other words, ASP .NET was not nulling out the data stored in the CallContext between requests...and thus an unauthenticated user might get into the application if they picked up a thread which still had the CallContext containing validated user identity info.
Let me tell you about a non-obvious danger :)
I used threads to collect Update some RSS feeds into my database for a website I was hosting with GoDaddy. The threads worked fine (if they were terminated, they would be restarted automatically due to some checks I had built in some web pages).
It was working excellently and I was very happy, until GoDaddy (my host then) first started killing the threads, and then blocked them completely. So my app just died!
If that wasn't non-obvious, what is?
One could be are you overly complicating your architecture without getting any benefits.
You program will be more expensive to write, more expensive to maintain and have a greater chance of having bugs.

Categories

Resources