UI不应该在后台处理时被冻结



我正在研究传统应用程序(winform App),我需要提高性能。

在这个应用程序中,我们使用MVP模式和Shell使用反射来查找需要调用哪个演示者以满足用户请求。因此,有一个函数可以完成以下任务…

  1. 查找合适的演示者
  2. 遍历所有的方法,找出默认的方法引用
  3. 为方法的参数输入准备数组
  4. 调用演示者的默认方法
  5. 返回演示者引用

下面是一些代码…

 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;
        }

此方法大约需要15-20秒来完成并冻结UI。我想用一些异步处理来反映这个方法,所以UI在这个方法期间不会冻结。由于我需要返回演示者引用,我想到使用wait()或join()方法,但它们会再次锁定UI。

请注意,我使用的是。net 4.0

除非你有数百万个演示者类型要搜索,这是非常值得怀疑的,除非你的演示者平均有数百万个参数,这也是非常值得怀疑的,否则我上面看到的代码中没有任何东西应该花费15秒来执行。

所以,整个延迟并不在你给我们看的代码中,而是在它调用的一个函数中。

这可能是在非常可疑的_presenterFactory.Create(pType);paramDictionary的实现中,如果它碰巧是一个滚动自己的字典而不是标准哈希字典,或者在method.Invoke(presenter, results);本身的调用中。

最有可能在最后。

所以,首先,剖析你的代码,找出真正的罪魁祸首是什么。

然后,重构你的代码,使冗长的进程发生在一个单独的工作线程上。这可能需要您将应用程序的相当一部分从GUI线程中取出并放入该工作线程中。没有人说GUI编程很容易。

如果罪魁祸首是method.Invoke(),那么这看起来像是您可以相对容易地移动到另一个线程:在返回之前启动该线程,并确保每个呈现者对象所发生的一切都是线程安全的。

但是,当然,这些演示者正在尝试在GUI中实际呈现内容,那么你将不得不去重构所有这些内容,将它们的计算昂贵的逻辑从呈现逻辑中分离出来,因为WinForms只能从自己的线程中调用。

最简单的方法是在foreach循环中使用Application.DoEvents();,以在长时间运行的进程中保持UI解锁

您可以参考MSDN system.windows.forms.application.doevents
但是在使用它之前,你还必须阅读保持你的UI响应和应用程序的危险。DoEvents

嗯,根据你的评论:"我的问题是我如何通过在后台放置一些不锁定UI的任务来反映这一点。"

试试这个:

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.");
    }
}

对不起,我不是一个Winforms家伙....在WPF中,我们有Dispatcher来处理线程关联问题。你可以试试这个:System.Windows.Threading.Dispatcher和WinForms?

相关内容

  • 没有找到相关文章

最新更新