Executing a method dynamically
Many times i am using code like this:
public static void ExecuteMethod1InThread(string msg)
{
Thread t = new Thread(
new ThreadStart(
delegate
{
log(msg);
}));
t.IsBackground = true;
t.Start();
t.Join();
}
If 开发者_如何学编程you notice i am calling a method in a separate thread hoping it would be helpful in performance.
But I am wondering if it is possible to give the method name and parameters dynamically and have it execute it rather than creating blocks of code like above for every method call.
I know we could use reflection but it will affect the performance is my understanding.
I have also heard about anonymous delegates but i am not sure how they work. Just wondering if anyone could enlighten.
(Read to the bottom for a crucial point!)
Well, you're already using an anonymous method. You can keep using C# 2.0 and make the code somewhat shorter like this:
public static void ExecuteMethod1InThread(string msg)
{
Thread t = new Thread(delegate() { log(msg); });
t.IsBackground = true;
t.Start();
t.Join();
}
Or you could use a lambda expression from C# 3:
public static void ExecuteMethod1InThread(string msg)
{
Thread t = new Thread(() => log(msg));
t.IsBackground = true;
t.Start();
t.Join();
}
Now you can make this simpler for calling different methods like this:
public static void ExecuteMethodInThread<T>(Action<T> method, T argument)
{
Thread t = new Thread(() => method(argument));
t.IsBackground = true;
t.Start();
t.Join();
}
You'd then call this with:
ExecuteMethodInThread(Log, "message");
ExecuteMethodInThread(DifferentMethod, 10);
(for example).
Alternatively, you could change it to just take a ThreadStart to start with:
public static void ExecuteMethodInThread(ThreadStart action)
{
Thread t = new Thread(action);
t.IsBackground = true;
t.Start();
t.Join();
}
and call it like this:
ExecuteMethodInThread(() => Log("Message"));
ExecuteMethodInThread(() => DoSomethingElse(20));
This isn't quite equivalent, however, due to when various expressions are evaluated. In particular, doing this in a loop could cause the problems Eric Lippert describes here.
Important point
However, what you've currently got will hurt performance. You're starting a new thread (rather than using the thread-pool) and then you're waiting for the thread to finish. This is effectively calling the log
method synchronously - how can that help performance?
Threads are commonly used to do multiple things at the same time.
For instance, you might want to download a webpage, analyze its contents, and use some values from it. At the same time, while the page is downloading, you might want to load some data from the database, to use together with the values from the webpage.
So you could do this:
------+------ read from database ----------------+--- process data Thread #1
\ /
\ /
+--- download and analyze webpage ---+ Thread #2
However, in your case, you do this:
------+ +--- process data Thread #1
\ /
\ /
+--- log(msg) -----------------------+ Thread #2
This makes no sense, and only adds overhead to your code.
I would simply rewrite your example to this:
public static void ExecuteMethod1InThread(string msg)
{
log(msg);
}
The net effect will be the same.
Actually, the above code will not help improve performance because of t.Join(). The nature of this method is to wait until the thread completes. So your main thread will wait and no parallelism will take place.
Unless the work in the delegate is rather elaborate, spawning a new thread will probably take more time than just doing the work on the thread at hand.
For short running tasks, you should generally prefer the ThreadPool. It has various options for scheduling jobs. It will not always be the perfect fit, but as it amortizes the cost of spawning new threads for short running tasks it will be a lot more efficient than spawning a thread for each new task.
Popping a message box in a new thread is not the smartest thing to do but, to only give an example,
WaitCallback cb = new WaitCallback(state =>
{
MessageBox.Show(state.ToString());
});
private void SomeMethod()
{
ThreadPool.QueueUserWorkItem(cb, "test");
}
EDIT:
WaitCallback logger = new WaitCallback(msg =>
{
log(msg.ToString());
});
public static void ExecuteMethod1InThread(string msg)
{
ThreadPool.QueueUserWorkItem(logger, msg);
}
精彩评论