Reputation: 903
I am working on legacy application (winform App) where I need to improve performance.
In this application, we are using MVP pattern and Shell usage reflection to find which presenter it needs to call in order to satisfied the user request. So there is a function which do the following tasks...
here is some code...
public object FindPresenter(Type pType, string action, Dictionary<string, object> paramDictonary, string callerName = null)
{
if (pType == null)
{
throw new ArgumentNullException("presenterType");
}
var presenterTypeName = pType.Name;
var presenter = _presenterFactory.Create(pType);
presenter.CallerName = callerName;
if (presenter == null)
{
throw new SomeException(string.Format("Unable to resolve presenter"));
}
// Check each interface for the named method
MethodInfo method = null;
foreach (var i in presenter.GetType().GetInterfaces())
{
method = i.GetMethod(action, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null) break;
}
if (method == null)
{
throw new SomeException(string.Format("No action method found"));
}
// Match up parameters
var par = method.GetParameters();
object[] results = null;
if (paramDictonary != null)
{
if (par.Length != paramDictonary.Count)
throw new ArgumentException(
"Parameter mis-match");
results = (from d in paramDictonary
join p in par on d.Key equals p.Name
orderby p.Position
select d.Value).ToArray();
}
// Attach release action
presenter.ReleaseAction = () => _presenterFactory.Release(presenter);
// Invoke target method
method.Invoke(presenter, results);
return presenter;
}
This method take around 15-20 second to complete and freeze the UI. I want to refector this method with some async processing so UI is not freeze during this method. As I need to return presenter reference, I thought of using wait() or join() method, but they will again lock the UI.
Please note, I am using .NET 4.0.
Upvotes: 0
Views: 90
Reputation:
Well, based on your comment: "My question is how can I refector this by putting some tasks in background which do not lock the UI."
Try this:
class Program
{
static void Main(string[] args)
{
Task t1 = Task.Run(() => FindPresenter(typeof(Program), "boo"))
.ContinueWith(x => UsePresenter(x.Result));
while (true)
{
Thread.Sleep(200);
Console.WriteLine("I am the ui thread. Press a key to exit.");
if ( Console.KeyAvailable)
break;
}
}
static object FindPresenter(Type type, string action)
{
// Your FindPresenter logic here
Thread.Sleep(1000);
return (object)"I'm a presenter";
}
static void UsePresenter(object presenter)
{
Console.WriteLine(presenter.ToString());
Console.WriteLine("Done using presenter.");
}
}
Sorry I am not a Winforms guy.... In WPF we have Dispatcher for thread affinity issues. You might try this: System.Windows.Threading.Dispatcher and WinForms?
Upvotes: 0
Reputation: 62120
Unless you have millions of presenter types to search through, which is highly doubtful, and unless your average presenter has millions of parameters, which is also highly doubtful, there is nothing in the code that I see above that should take 15 seconds to execute.
So, the entirety of the delay is not in the code that you are showing us, but in one of the functions it invokes.
That could be in the very suspicious looking _presenterFactory.Create(pType);
or in the implementation of paramDictionary
if by any chance it happens to be a roll-your-own dictionary instead of a standard hash dictionary, or in the invocation of method.Invoke(presenter, results);
itself.
Most likely in the last.
So, first of all, profile your code to find what the real culprit is.
Then, restructure your code so that the lengthy process happens on a separate worker thread. This may require that you pull considerable parts of your application out of the GUI thread and into that worker thread. Nobody said GUI programming was easy.
If the culprit is method.Invoke()
, then this looks like something that you may be able to move to another thread relatively easily: Start that thread right before returning, and make sure everything that happens with each one of those presenter objects is thread safe.
But of course, these presenters are trying to actually render stuff in the GUI, then you will have to go and refactor all of them too, to separate their computationally expensive logic from the rendering logic, because WinForms can only be invoked from within its own thread.
Upvotes: 1
Reputation: 2752
The easiest approach is to use Application.DoEvents();
in your foreach
loop to keep UI unlocked during long running processes
You may refer to MSDN system.windows.forms.application.doevents
But before using it you must also read Keeping your UI Responsive and the Dangers of Application.DoEvents
Upvotes: 0