ashwin_k_s

Hi,

I have application where I am showing couple of database servers in datagrid. I am using some logic to update selected databases. I am using following code in my application:

AsyncDelegate del = new AsyncDelegate(BeginProcess);

AsyncCallback cb = new AsyncCallback(EndProcess);

IAsyncResult ar = del.BeginInvoke(cb, del);

In BeginProcess function, I am iterating through datagrid items in for loop and if a database server is selected, calls the logic for updating database. This approach is consuming lots of time. I am not clear about as to how to approach this problem using multithreading. I am working on windows application. I am new to windows application and have read articles on multuthreading. Still not sure hoe to proceed to solve this problem. Any help will be appreciated.

Regards,




Re: Visual C# Language How to use multithreading in for loop?

Alberto Poblacion

If you are updating multiple databases and the databases are slow to respond, you may consider starting a new thread for each database, rather than starting a single thread that loops through all the databases. This will reduce the total time needed to complete the operations, assuming that the databases are on different servers or on a single server that can scale if it receives multiple queries at the same time (for instance, if it has multiple CPUs and multiple spindles for the database files).

If there are many databases, you will want to establish a limit for the number of updates in progress at a given time, so as not to launch dozens of simultaneous threads.

The async delegate that you are using is reasonable, but is not the only way to launch the threads. A different approach is to create a System.Threading.Thread to start the different threads. This lets you adjust the priority of each thread you are launching. Another possibility, if you are using Sql Server databases, is to use the BeginExecuteNonQuery and similar methods of the SqlCommand object to send the command that updates you databases.





Re: Visual C# Language How to use multithreading in for loop?

ashwin_k_s

Hi Alberto,

Thanks for your reply. In my scenario, there may be a case when 10-12 databases will get updated. The application that I have is of client and I don't want to manipulate too much in it. Like I mentioned in my previous post that application is using ASync delegate at present. There are other things in the BeginProcess function that are being done, in addition to database updates.So, I am looking for an approach that will provide optimized result without too much tinkering with present code. Is it possible to open threads for each database update inside BeginProcess function I know that you have mentioned to be aware of this in your post, but, can i do it inside async delegate function.

Regards,






Re: Visual C# Language How to use multithreading in for loop?

Alberto Poblacion

Yes, inside any given thread, including one started by means of an async delegate, you can start another new thread by means any of the alternative methods, including the use of yet another async delegate.

Be careful if you are starting many threads with async delegates, because they use the ThreadPool which has a limit on the number of threads that it can provide to your code.

If there are other thigs being done in the BeginProcess function, and these things operate with class variables, you want to be careful if you launch them in separate threads, in order to avoid race conditions. You will need to add appropriate locking when accessing resources that are shared by several threads. This is not needed when calling the database, since the database itself performs the locking (but you need to use separate Connections unless you are using MARS).





Re: Visual C# Language How to use multithreading in for loop?

ashwin_k_s

Hi Alberto,

If I could get any reference link where I can get to know how these things (threads, multithreading) work in actual. I have gone through some tutorials on threading, but, not sure how to get started on this and still looking for first step.Thanks again for your reply.

Regards






Re: Visual C# Language How to use multithreading in for loop?

Alberto Poblacion

The source where I first learned about multithreading in .Net was Microsoft Official Course 2349, which contains a chapter on this subject, but these MOC courses are only available at significant cost, so this may not be an option for you. Other than that, my only suggestion is to look up the System.Threading namespace in the MSDN library and follow the various links from there.





Re: Visual C# Language How to use multithreading in for loop?

ashwin_k_s

Hi Alberto,

Just wanted to know your suggestion for the following code as to how you see I can implement threading in it. This is part of BeginProcess function where I am checking database servers to be updated.

proc = UpdateLogic.Process.CreateObject(drv.Row["Class"].ToString(), drv.Row["Assembly"].ToString());

for(int x=0;x<dbs.Length;x++)

{

if(conn[x].State == ConnectionState.Closed)

conn[x].Open();

if(tran[x] == null)

tran[x] = conn[x].BeginTransaction();

tStart = DateTime.Now;

try

{

System.Diagnostics.Trace.WriteLine(rv.Row["Name"].ToString() + " on database '" + conn[x].ConnectionString + "' started at " + tStart.ToString());

System.Diagnostics.Trace.WriteLine("");

System.Diagnostics.Trace.Indent();

proc.Update(tran[x]); //calls overridden method of the class

}

catch(Exception ex)

{

LogError(ex.Message, ex);

sb.Append(ex.Message);

sb.Append("\r\n");

}

finally

{

tEnd = DateTime.Now;

span = tEnd - tStart;

System.Diagnostics.Trace.Unindent();

System.Diagnostics.Trace.WriteLine("");

System.Diagnostics.Trace.WriteLine(drv.Row["Name"].ToString() + " on database '" + conn[x].ConnectionString + "' ended at " + tEnd.ToString() + ". Duration : " + span.Minutes + " min " + span.Seconds + " sec");

System.Diagnostics.Trace.WriteLine("");

}

}

for(int x=0;x<gdbs.Length;x++)

{

try

{

if(bError == false)

{

System.Diagnostics.Trace.WriteLine("Committing " + drv.Row["Name"].ToString() + " on database '" + conn[x].ConnectionString + "'");

System.Diagnostics.Trace.WriteLine("");

tran[x].Commit();

}

else

{

System.Diagnostics.Trace.WriteLine("Undoing " + drv.Row["Name"].ToString() + " on database '" + conn[x].ConnectionString + "'");

System.Diagnostics.Trace.WriteLine("");

tran[x].Rollback();

textBox1.BackColor = Color.Red;

}

}

catch(Exception ex)

{

System.Diagnostics.Trace.WriteLine("Undoing " + drv.Row["Name"].ToString() + " on database '" + conn[x].ConnectionString + "'");

System.Diagnostics.Trace.WriteLine("");

tran[x].Rollback();

LogError(ex.Message, ex);

sb.Append(ex.Message);

sb.Append("\r\n");

}

finally

{

conn[x].Close();

tran[x] = null;

}

}

Regards






Re: Visual C# Language How to use multithreading in for loop?

Alberto Poblacion

It's a little bit complex. My first idea would be to start a thread inside of the "for" loop so that each of the database operations would be processed in parallel. Each has its own database connection, so this wouldn't be a problem. However, there are various things that would have to be taken care of.

First, there is your "proc" object that does an "Update" inside the loop. Depending on what this method does inside, it could be unsafe for multithreading, so it would have to be examined and locking applied if needed.

Then, there is all the logging and tracing logic, which is definitely NOT safe for multithreading. For instance, the stringbuilder "sb" where you Append the error messages would get all messed up if two of the threads tried to append messages at the same time. Same thing goes for the various Trace instructions performed in sequence: if two threads execute this code at the same time, your trace will intermix the various writes and indents, producing a result that is not what you expect.

It can all be fixed for multithreaded work by means of carefully placed lock() statements, but it requires detailed consideration. It would be simple if you just wanted to send Sql Commands in parallel to various databases, but the additional code needs to be analyzed for possible impact when ran from several threads.

Also, you would be updating UI elements from the thread inside the loop, namely the textBox1.BackColor. This is not allowed in Windows Forms: The form controls can only be updated from the same thread that created them, so you have to marshall execution accross threads by means of the Invoke method of the Form or Control. This is not terribly complex if you know how to do it, but it adds yet another consideration that you need to keep in mind.

All things considered, I think that it would be best to try to refactor the code so that the database update operations (which are the ones that are slow and that you wish to perform in parallel) are isolated from all the surrounding logic, and wherever this is not possible, add locking around the operations that are not safe for multithreading.





Re: Visual C# Language How to use multithreading in for loop?

ashwin_k_s

Hi Alberto,

Your have been very helpful. I will keep these points in mind before starting any change. Thanks for your immense help in understanding what I should be aware of while implementing multithreading.

Regards






Re: Visual C# Language How to use multithreading in for loop?

Peter Ritchie

You shouldn't access a .NET Windows control from a thread other than the thread that created the control.

What are you hoping to accomplish with multiple threads Simply adding threads isn't going to make something appear to run faster; and in many cases it makes it run slower because of the added overhead of creating and running multiple threads.






Re: Visual C# Language How to use multithreading in for loop?

Alberto Poblacion

What the Original Poster wanted to accomplish is to send various requests to several database servers at the same time. Sending them in parallel using multiple threads will get the task completed in a time that is similar to the slowest of the responses from the various servers. If the operations are done sequentially, the total time is the sum of the response times of all the servers, which can potentially be much more time than the slowest of them all.

About accessing a Windows control from another thread, do notice that I already warned the OP in a previous message about the requirement to marshall the execution into the thread that created the window by means of the Invoke method.