[.net] Multi-threading web services in C#

Started by
4 comments, last by ernow 18 years, 4 months ago
I'm currently developing an app for work which is to be used to test the connectivity to web services in order to verify new environment builds. This section of it is working correctly, however there is over 2000 web methods that need to be tested and this takes around an hour to execute. I'm hoping to cut down this time by multi-threading my app but am not having too much success with it (haven't done this sort of coding since university). I have managed to get basic threading working with just using the Thread.Sleep() method however when trying to convert this logic to invoking web methods I am not seeing any performance gain. This is my current code:

public class Form1 : System.Windows.Forms.Form
{
	DateTime d1, d2;
	TimeSpan ts;
	int nItem, nThreads;
	ThreadStart asdf = null;

	public Form1()
	{
		nItem = 0;
		nThreads = 0;
		asdf = new ThreadStart(ThreadFunc);
		InitializeComponent();
	}

	private void cmdExecuteThreaded_Click(object sender, System.EventArgs e)
	{
		d1 = DateTime.Now;
		nItem = 0;
		listView1.Items.Clear();
		nThreads = 5;
		Thread t1 = new Thread(asdf);
		t1.Name = "asdf1";
		t1.Start();
		Thread t2 = new Thread(asdf);
		t2.Name = "asdf2";
		t2.Start();
		Thread t3 = new Thread(asdf);
		t3.Name = "asdf3";
		t3.Start();
		Thread t4 = new Thread(asdf);
		t4.Name = "asdf4";
		t4.Start();
		Thread t5 = new Thread(asdf);
		t5.Name = "asdf5";
		t5.Start();
	}

	public void ThreadFunc()
	{
		string strMethod = "", strFilename = "", strURL = "", strResult = "";
		Monitor.Enter(this);
		strMethod = cboMethods.Items[nItem].ToString();
		strFilename = "Data\\test.asmx - " + strMethod + ".txt";
		strURL = "http://testurl/test.asmx";
		strResult = InvokeService(strFilename, strURL, strMethod);
		LoadViewList(strResult);
		nItem++;
		Monitor.Exit(this);
		if (nItem < cboMethods.Items.Count - 4)
		{
			Thread tNew = new Thread(asdf);
			tNew.Name = Thread.CurrentThread.Name;
			tNew.Start();
			nThreads++;
		}
		nThreads--;
		if (nThreads == 0)
		{
			ThreadFuncDone();
		}
	}

	public void ThreadFuncDone()
	{
		d2 = DateTime.Now;
		ts = d2 - d1;
		MessageBox.Show(ts.TotalSeconds.ToString());
	}

	public void LoadViewList(string strData)
	{
		string[] arrData = strData.Split('$');
		ListViewItem item = new ListViewItem(arrData[0]);
		item.SubItems.Add(arrData[1]);
		item.SubItems.Add(arrData[2]);
		item.SubItems.Add(arrData[3]);
		item.SubItems.Add(arrData[4]);
		listView1.Items.Add(item);
	}

	public string InvokeService(string strFilename, string strService, string strMethod)
	{
		string strResult = "";
		try
		{
			//Generate XML request here...
			strResult = "PASS$" + strService + "$" + strMethod + "$" + "Execution Status$" + currentNode.text;
		}
		catch (Exception e)
		{
			strResult = "FAIL$" + strService + "$" + strMethod + "$" + "Exception$" + e.Message + " - " + e.ToString();
		}
		return strResult;
	}
}

Any ideas where this is going wrong?
Advertisement
Instead of mucking about with manually creating threads, why don't you invoke the web methods asynchronously? For each web method Foo() that's generated by the proxy generator, there should be an equivalent asynchronous method, FooAsync(), accompanied by a FooCompleted() event.
--AnkhSVN - A Visual Studio .NET Addin for the Subversion version control system.[Project site] [IRC channel] [Blog]
Because of the "Monitor.Enter(this);" you push all threads but one in a waiting queue (as far as I can see)

Are you sure you are profiling the right part? When the web service is slow this won't help.

And btw: don't access form-controls on a different thread than the thread they were created on.

cheers
Well I've tried moving the Monitor.Enter/Exit around and it seems to work. My code now looks like this:

//MessageBox.Show("pre");Monitor.Enter(this);strMethod = cboMethods.Items[nItem].ToString();nItem++;strFilename = "Data\\test.asmx - " + strMethod + ".txt";strURL = "http://testurl/test.asmx";Monitor.Exit(this);strResult = InvokeService(strFilename, strURL, strMethod);LoadViewList(strResult);//MessageBox.Show("post");

The problem that I have now is that my five initial threads are started and simply seem to hang doing nothing. However if I uncomment the "pre" & "post" message boxes it all seems to run correctly. Any way of getting this running without the message boxes in place as it's not going to be practical having to click 4000 of them?
you are still accessing controls on threads other than the creating thread! By showing the messagebox you boost the creating thread and thus 'unlock' the executing thread. In LoadListview use this.Invoke(...) instead of directly modifying the listview.

Cheers
Found this blog entry that explains it in more detail:
Evil trick to render UI when stopped at a breakpoint.

Cheers

This topic is closed to new replies.

Advertisement