Implementing thread pool for stored procedure calls - c#

First, let me start with saying that I am a C# beginner. My background has mostly been with databases. I am working on a project where there will be frequent calls to a C# server which then calls various stored procedures (about 20 or so) to retrieve data from a SQL Server DB. Right now, the C# server was set up doing synchronous calls. While the SP calls are quick and small, we would still like to implement a thread pool to handle a large pool of users and simultaneous requests.
My questions:
How do I implement a thread pool? Most likely, the thread pool will start around 500, but could grow depending on use of the application.
How do I add the SP calls to the thread pool. Right now my SP call looks like this:
int SPCall(string param1, string param2)
{
string MyConnString = "...";
SqlConnection MyConn = new SqlConnection(MyConnString);
MyConn.Open();
SqlCommand SPCommand = new SqlCommand("wh_SP");
SPCommand.Connection = MyConn;
SPCommand.Parameters.Add(...) = param1;
SPCommand.Parameters.Add(...) = param2;
SPCommand.CommandType = System.Data.CommandType.StoredProcedure;
SPCommand.ExecuteNonQuery();
int outPut = (int)SPCommand.Parameters["#OUTPUT"].Value;
return outPut;
}

As mentioned in the comments, you should use the .NET ThreadPool instead of implementing your own. Even better, use the newer .NET Parallel library and chunk each of these out into a task. You will have far better control over how your concurrency is handled with relatively little code.
public void PerformWork()
{
// setup your inputs
IEnumerable<string> inputs = CreateYourInputList();
// Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
Parallel.ForEach(inputs, input =>
{
// call your code that issues the stored procedure here
this.SPCall(input);
} //close lambda expression
); //close method invocation
// Keep the console window open in debug mode.
Console.WriteLine("Processing complete. Press any key to exit.");
Console.ReadKey();
}

Related

How to make this asynchronous? (async, await - C#, MVC)

I just tried to make a part of my ASP .NET MVC Application asynchronous but even after reading and trying out a lot I don't really understand the async-await pattern and hope someone could give me a hint.
Basically I have the following:
A javascript call to my controller which fetches a partial View for a chart (this happens several times after page load for a lot of charts)
// Load content of one chart
my.loadChartContent = function (data, callback) {
$.post("/Dashboard/GetChartContent/", data, function (datain) {
if (isFunction(callback))
callback(datain);
});
};
A controller action which calls a database method in another class
public ActionResult GetChartContent(int id, bool isDraft = false)
{
//do something
//...
var chartdata = _dataService.GetDataForChart(chart, isDraft, _user.Id); //long running query
//do something with chartdata
return View(chartdata);
}
The data class (_dataService) which fetches the data from the database with a SqlDataReader and loads a DataTable with that data.
The problem is that although the javascript is executed asynchronously the Controller-Actions seems to be blocked until a result from the DataService class returns. I would like to start all queries to the database and wait for the results asynchronously, so that long-running queries don't block shorter ones. (In SQL Server Profiler I see the queries as Begin-End, Begin-End, Begin-End => but it should be begin-begin-begin - end-end-end)
Where should I use async-await? Is it enough to use it (somehow) for my controller action or is it necessary to make the whole "call-chain" asynchronous?
Update:
When I use SQLConnection.OpenAsync and ExecuteReaderAsync the code never finishes...and I don't get why?
public async Task<Query> GetSqlServerData(Query query)
{
var dt = new DataTable();
var con = new SqlConnection(query.ConnectionString);
await con.OpenAsync();
var cmd = new SqlCommand(query.SelectStatement, con);
var datareader = await cmd.ExecuteReaderAsync();
dt.Load(datareader);
con.Close();
query.Result = dt;
return query;
}
Thank you all for your answers. But the real answer is way simpler than I thought. Stephen pointed me in the right direction with the sentence
All HTTP calls are naturally asynchronous.
I knew that and generally that's true but obviously not when you're using sessions because ASP.NET MVC waits for each request (from one user) to be completed to synchronize the session. You can find a better explanation here: http://www.stefanprodan.eu/2012/02/parallel-processing-of-concurrent-ajax-requests-in-asp-net-mvc/
So - just decorating my controller with ...
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
...did it and now I have the result I wanted - simultaneous queries on my SQL Server and a lot faster response time.
#Stephen - it's more than 2 simultaneous requests => http://www.browserscope.org/?category=network
The problem is that although the javascript is executed asynchronously the Controller-Actions seems to be blocked until a result from the DataService class returns. I would like to start all queries to the database and wait for the results asynchronously, so that long-running queries don't block shorter ones.
The term "asynchronous" can be applied a few different ways. In JavaScript, everything is asynchronous. All HTTP calls are naturally asynchronous.
If you're not seeing any sql overlapping, then you should be sure that you're calling loadChartContent multiple times (not calling it once at a time chained through callbacks or anything like that). The browser will limit you to two simultaneous requests, but you should see two requests at a time hitting your sql server.
Making your server side async won't help you, because async doesn't change the HTTP protocol (as I describe on my blog). Even if you make your database access async, your controller action will still have to wait for them to complete, and the browser will still limit you to two outstanding requests. Server-side async is useful for scaling your web servers, but if your web server is talking to a single SQL Server backend, then there's no point in scaling your web server because your web server is not the determining factor in your scalability.
On a side note, I suspect the reason your async code never finishes is because you're using Result or Wait; I explain this on my blog.
So, back to your original problem: if you want to start all the queries to the database, then you'll need to change API to be "chunky" instead of "chatty". I.e., add a GetChartContents action which takes multiple ids and runs all of those queries in parallel. I'd recommend using async database methods with something like this:
public async Task<ActionResult> GetChartContents(int[] ids, bool isDraft = false)
{
var charts = ...;
var chartTasks = Enumerable.Range(0, ids.Length)
.Select(i => _dataService.GetDataForChartAsync(charts[i], isDraft, _user.Id))
.ToArray();
var results = await Task.WhenAll(chartTasks);
...
return View(results);
}
I think this tutorial gives a pretty good starting point for what you're trying to do.
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
If you have:
public async Task<Query> GetSqlServerData(Query query)
{
var dt = new DataTable();
var con = new SqlConnection(query.ConnectionString);
await con.OpenAsync();
var cmd = new SqlCommand(query.SelectStatement, con);
var datareader = await cmd.ExecuteReaderAsync();
dt.Load(datareader);
con.Close();
query.Result = dt;
return query;
}
Then use:
query1 = await GetSqlServerData(query1);
query2 = await GetSqlServerData(query2);
query3 = await GetSqlServerData(query3);

Which is better, decreasing or increasing ADO.NET SQL Connections?

I have a multi-threaded windows application using more that a background worker. every background worker is using some code to update the same SQL Server database and when it finished it runs again. I have noticed that every background worker is using a single connection. I have created a ConcurrentQueue of a custom class to add all the stored procedures to it and execute it from a single backgorundworker to use just one connection as the database is getting very slow when using many connections.
here is my code
this is the stored procedure class
string _procName;
Dictionary<string, object> _parameters;
public string ProcName
{
get { return _procName; }
set { _procName = value; }
}
public Dictionary<string, object> Parameters
{
get { return _parameters; }
set { _parameters = value; }
}
public PSCProc(string procName, Dictionary<string, object> parameters)
{
_procName = procName;
_parameters = parameters;
}
and here is the method used to run the stored procedure
public static void execProc(string procName, Dictionary<string, object> parameters)
{
using (var conn = new SqlConnection(Test.Properties.Settings.Default.testConnection))
using (var command = new SqlCommand(procName, conn)
{
CommandType = CommandType.StoredProcedure
})
{
foreach (var item in parameters)
{
command.Parameters.AddWithValue(item.Key, item.Value);
}
conn.Open();
command.ExecuteNonQuery();
conn.Close();
Form1.updated++;
}
}
and this is how i add an item to the queue
Dictionary<string, object> parameters = new Dictionary<string, object>();
int x = 1;
string address = "cairo";
parameters.Add("#id", x);
parameters.Add("#address", address);
PSCProc proc1 = new PSCProc("updateAddress", parameters);
pscQueue.Enqueue(proc1);
and this how i run the background worker to run the procedures
PSCProc proc;
if (pscQueue.TryDequeue(out proc))
{
helper.execProc(proc.ProcName, proc.Parameters);
}
Note that:
-the background worker that executes the procedures runs again when it finished.
-the database has too many locks as there are hundreds using it.
-the database is very important to be responsive all the time without any locks.
-connection pooling is saving the connections sleeping or suspended all the time.
-the ratio of adding procedures to the queue won't be faster that the ratio of executing them.
My Question Is
Is it better to use this way or using many connections won't affect the Database.
I would make a SQL Agent job that runs your stored procedure. Then your connection can login, start the job, and exit, and SQL Agent will run the job in the background. That way your connections aren't held open while the procedure runs.
That being said, I'll bet your database isn't slow because there are lots of connections, I'll bet it's slow because it's running lots of queries on behalf of those connections. But without knowing the code of your stored procedure nor your schema it's really impossible to know.
The amount of connections could slowdown the SQL Server depending on the actual amount.
One way of slimming down could be by checking whether or not the application is using connection pooling correctly. See this MSDN article for getting it right. A lot depends on the connection string and the state a connection is left in. (If there are open transactions, different credentials it can't be pooled)
Another way is moving the execution of the procedure(s) to a central service and have that service cache the database requests/responses.
Finally I'd have a look at the procedures/queries themselves; you mention that there is a lot of locking going on. Try and find out why. Did you create an insert hotspot at the end of a table? An index might help removing the hotspot. An (insert) trigger might be in the way. See this post for more details

Thread Monitor class in c#

In my c# application multiple clients will access the same server, to process one client ata a time below code is written.In the code i used Moniter class and also the queue class.will this code affect the performance.if i use Monitor class, then shall i remove queue class from the code.
Sometimes my remote server machine where my application running as service is totally down.is the below code is the reasond behind, coz all the clients go in a queue, when i check the netstatus -an command using command prompt, for 8 clients it shows 50 connections are holding in Time-wait...
Below is my code where client acces the server ...
if (Id == "")
{
System.Threading.Monitor.Enter(this);
try
{
if (Request.AcceptTypes == null)
{
queue.Enqueue(Request.QueryString["sessionid"].Value);
string que = "";
que = queue.Dequeue();
TypeController.session_id = que;
langStr = SessionDatabase.Language;
filter = new AllThingzFilter(SessionDatabase, parameters, langStr);
TypeController.session_id = "";
filter.Execute();
Request.Clear();
return filter.XML;
}
else
{
TypeController.session_id = "";
filter = new AllThingzFilter(SessionDatabase, parameters, langStr);
filter.Execute();
}
}
finally
{
System.Threading.Monitor.Exit(this);
}
}
Locking this is pretty wrong, it won't work at all if every thread uses a different instance of whatever class this code lives in. It isn't clear from the snippet if that's the case but fix that first. Create a separate object just to store the lock and make it static or give it the same scope as the shared object you are trying to protect (also not clear).
You might still have trouble since this sounds like a deadlock rather than a race. Deadlocks are pretty easy to troubleshoot with the debugger since the code got stuck and is not executing at all. Debug + Break All, then Debug + Windows + Threads. Locate the worker threads in the thread list. Double click one to select it and use Debug + Call Stack to see where it got stuck. Repeat for other threads. Look back through the stack trace to see where one of them acquired a lock and compare to other threads to see what lock they are blocking on.
That could still be tricky if the deadlock is intricate and involves multiple interleaved locks. In which case logging might help. Really hard to diagnose mandelbugs might require a rewrite that cuts back on the amount of threading.

C# Multithreaded application and SQL connections help

I need some advice regarding an application I wrote. The issues I am having are due to my DAL and connections to my SQL Server 2008 database not being closed, however I have looked at my code and each connection is always being closed.
The application is a multithreaded application that retrieves a set of records and while it processes a record it updates information about it.
Here is the flow:
The administrator has the ability to set the number of threads to run and how many records per thread to pull.
Here is the code that runs after they click start:
Adapters are abstractions to my DAL here is a sample of what they look like:
public class UserDetailsAdapter: IDataAdapter<UserDetails>
{
private IUserDetailFactory _factory;
public UserDetailsAdapter()
{
_factory = new CampaignFactory();
}
public UserDetails FindById(int id){
return _factory.FindById(id);
}
}
As soon as the _factory is called it processes the SQL and immediately closes the connection.
Code For Threaded App:
private int _recordsPerthread;
private int _threadCount;
public void RunDetails()
{
//create an adapter instance that is an abstration
//of the data factory layer
var adapter = new UserDetailsAdapter();
for (var i = 1; i <= _threadCount; i++)
{
//This adater makes a call tot he databse to pull X amount of records and
//set a lock filed so the next set of records that are pulled are differnt.
var details = adapter.FindTopDetailsInQueue(_recordsPerthread);
if (details != null)
{
var parameters = new ArrayList {i, details};
ThreadPool.QueueUserWorkItem(ThreadWorker, parameters);
}
else
{
break;
}
}
}
private void ThreadWorker(object parametersList)
{
var parms = (ArrayList) parametersList;
var threadCount = (int) parms[0];
var details = (List<UserDetails>) parms[1];
var adapter = new DetailsAdapter();
//we keep running until there are no records left inthe Database
while (!_noRecordsInPool)
{
foreach (var detail in details)
{
var userAdapter = new UserAdapter();
var domainAdapter = new DomainAdapter();
var user = userAdapter.FindById(detail.UserId);
var domain = domainAdapter.FindById(detail.DomainId);
//...do some work here......
adapter.Update(detail);
}
if (!_noRecordsInPool)
{
details = adapter.FindTopDetailsInQueue(_recordsPerthread);
if (details == null || details.Count <= 0)
{
_noRecordsInPool = true;
break;
}
}
}
}
The app crashes because there seem to be connection issues to the database. Looking in my log files for the DAL I am seeing this:
Timeout expired. The timeout period
elapsed prior to obtaining a
connection from the pool. This may
have occurred because all pooled
connections were in use and max pool
size was reached
When I run this in one thread it works fine. I am guessing when I runt his in multiple threads I am obviously making too many connections to the DB. Any thoughts on how I can keep this running in multiple threads and make sure the database doesn’t give me any errors.
Update:
I am thinking my issues may be deadlocks in my database. Here is the code in SQL that is running whe I get a deadlock error:
WITH cte AS (
SELECT TOP (#topCount) *
FROM
dbo.UserDetails WITH (READPAST)
WHERE
dbo.UserDetails where IsLocked = 0)
UPDATE cte
SET
IsLocked = 1
OUTPUT INSERTED.*;
I have never had issues with this code before (in other applications). I reorganzied my Indexes as they were 99% fragmented. That didn't help. I am at a loss here.
I'm confused as to where in your code connections get opened, but you probably want your data adapters to implement IDispose (making sure to close the pool connection as you leave using scope) and wrap your code in using blocks:
using (adapter = new UserDetailsAdapter())
{
for (var i = 1; i <= _threadCount; i++)
{
[..]
}
} // adapter leaves scope here; connection is implicitly marked as no longer necessary
ADO.NET uses connection pooling, so there's no need to (and it can be counter-productive to) explicitly open and close connections.
It is not clear to me how you actually connect to the database. The adapter must reference a connection.
How do you actually initialize that connection?
If you use a new adapter for each thread, you must use a new connection for each adapter.
I am not too familiar with your environment, but I am certain that you really need a lot of open connections before your DB starts complaining about it!
Well, after doing some research I found that there might be a bug in SQL server 2008 and running parallel queries. I’ll have to dig up the link where I found the discussion on this, but I ended up running this on my server:
sp_configure 'max degree of parallelism', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO
This can decrease your server performance, overall, so it may not be an option for some people, but it worked great for me.
For some queries I added the MAXDOP(n) (n being the number of processors to utilize) option so they can run more efficiently. It did help a bit.
Secondly, I found out that my DAL’s Dispose method was using the GC.Suppressfinalize method. So, my finally sections were not firing in my DAL properly and not closing out my connections.
Thanks to all who gave their input!

BeginExecuteNonQuery without EndExecuteNonQuery

I have the following code:
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;")
{
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection))
{
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.BeginExecuteNonQuery();
}
}
I never call EndExecuteNonQuery.
Two questions, first will this block because of the using statements or any other reason? Second, will it break anything? Like leaks or connection problems? I just want to tell sql server to run a stored procedure, but I don't want to wait for it and I don't even care if it works. Is that possible? Thanks for reading.
This won't work because you're closing the connection while the query is still running. The best way to do this would be to use the threadpool, like this:
ThreadPool.QueueUserWorkItem(delegate {
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;") {
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection)) {
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.ExecuteNonQuery();
}
}
});
In general, when you call Begin_Whatever_, you usually must call End_Whatever_ or you'll leak memory. The big exception to this rule is Control.BeginInvoke.
You can't close the connection after you submit the BeginExceuteNotQuery. It will abort the execution. Remove the using block.
In order to close the connection, you must know when the call has completed. For that you must call EndExecuteNonQuery, usually from a callback:
.
command.BeginExecuteNonQuery(delegate (IAsyncResult ar) {
try { command.EndExecuteNonQuery(ar); }
catch(Exception e) { /* log exception e */ }
finally { sqlConnection.Dispose(); }
}, null);
If you want to submit a query and don't care about the results, see Asynchronous T-SQL execution for a reliable pattern that ensures execution even if client diconnects or crashes.
You should always call the EndExecuteNonQuery() method to prevent leaks. It may work now but who knows what will happen in future versions of .NET. The general rule is always follow a BeginExecute... with an EndExecute...
I know this is an old post; just adding my 2c based on our recent (very conclusive) implementation and testing :D
To answer the OP's questions:
If you don't call EndExecuteNonQuery, BeginExecuteNonQuery will execute the procedure, but the operation will be cancelled as soon as the using clause disposes of your sql connection. Hence this is not plausible.
If you call BeginExecuteNonQuery by using a delegate, creating a new thread etc and you do not call EndExecuteNonQuery, chances are good you might get memory leaks depending on what takes place in you stored procedure. (More on this later).
Calling an stored procedure and not waiting for the call to complete, as far I our testing went, is not possible. Irrespective of multitasking, something somewhere will have to wait.
On to our solution:
Refs: BeginExecuteNonQuery -> BENQ, EndExecuteNonQuery -> EENQ
Use Case:
We have a windows service (C#) that makes use of the .Net TPL library. We needed to load data with a stored procedure from one database to another at run time, based on a add hoc request that the service picks up. Our stored procedure had an internal transaction and exception handling with try catch blocks.
First Try:
For our first try we implemented a solution found here MS Solution in this example you will see that MS opts to call BENQ then implements a while loop to block execution and then calls EENQ. This solution was mainly implemented if you don't need a callback method. The problem with this solution is that only BENQ is ignorant to sql connection timeouts. EENQ will timeout. So for a long running query (which is hopefully the reason why you are using BENQ) you will get stuck in the while and once the operation has completed and you call EENQ, you will get an sql timeout connection.
Second Try:
For our second try we thought ok so lets call BENQ, then add a while so that we don't close our sql connection and never call EENQ. This worked, until an exception was thrown in our stored procedure. Because we never called EENQ, the operation was never completed and the exception never bubbled up to our code. Hence we were stuck in a loop/thread/memory leak forever.
Third Try: (The Solution)
For our third try we thought to call BENQ, then directly after call EENQ. What happened was that EENQ effectively blocked execution in the thread until the operation completed. When an exception occurred in the stored procedure it was caught. When the query ran long EENQ did not throw a timeout exception and in all cases our sql connection object was disposed as well as our thread.
Here are some extracts of our code:
Here we open up a new thread for the method that calls the stored procedure.
//Call the load data stored procedure. As this stored procedure can run longer we start it in its own thread.
Task.Factory.StartNew(() => ClassName.MethodName(Parameters));
This is the code inside the method we use to call the stored procedure.
//Because this is a long running stored procedure, we start is up in a new thread.
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionStringName"]].ConnectionString))
{
try
{
//Create a new instance SqlCommand.
SqlCommand command = new SqlCommand(ConfigurationManager.AppSettings["StoredProcedureName"], conn);
//Set the command type as stored procedure.
command.CommandType = CommandType.StoredProcedure;
//Create input parameters.
command.Parameters.Add(CreateInputParam("#Param1", SqlDbType.BigInt, Param1));
command.Parameters.Add(CreateInputParam("#Param2", SqlDbType.BigInt, Param3));
command.Parameters.Add(CreateInputParam("#Param3", SqlDbType.BigInt, Param3));
//Open up the sql connection.
conn.Open();
//Create a new instance of type IAsyncResult and call the sp asynchronously.
IAsyncResult result = command.BeginExecuteNonQuery();
//When the process has completed, we end the execution of the sp.
command.EndExecuteNonQuery(result);
}
catch (Exception err)
{
//Write to the log.
}
}
I hope this answer save's someone some headache :D We have tested this thoroughly and have not experienced any issues.
Happy coding!
In this case the using statements won't be necessary because you should manually close it yourself rather than allowing the syntactic sugar dispose it for you (i.e. at the }).
It should be as simple as this to ensure you don't have leaks.
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;")
{
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection))
{
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.BeginExecuteNonQuery((ar) =>
{
var cmd = (SqlCommand)ar.AsyncState;
cmd.EndExecuteNonQuery(ar);
cmd.Connection.Close();
}, command);
}
}
As you can see the lambda expression that is fired once the command is finished (no matter how long it takes) will do all the closing for you.

Categories

Resources