【问题标题】:Addins interop-access 15-20x faster than in a windows application插件互操作访问速度比 Windows 应用程序快 15-20 倍
【发布时间】:2018-06-04 14:13:54
【问题描述】:

我不知道 StackOverflow 是否适合询问性能问题,但我还没有找到更好的社区来解决这个问题。

基本上我们有两个示例程序,一个是插件,一个是引用 Word 互操作的 winforms 程序。

两者都实现了称为GetTabsFromParagraph的相同方法:

public class SlowExample
{
    public static void GetTabsFromParagraph(Paragraph para, Style style, List<Tabulator> tabList, bool getTabsForCase = false)
    {
        foreach (TabStop tab in para.TabStops)
        {
            if (tab.CustomTab)
            {
                bool showTab = true;
                foreach (TabStop ts in style.ParagraphFormat.TabStops)
                {
                    if (Math.Abs(ts.Position - tab.Position) < 0.001 &&
                        ts.Alignment == tab.Alignment)
                    {
                        showTab = false;
                        break;
                    }
                }
                if (showTab || getTabsForCase)
                {
                    Tabulator t = new Tabulator
                    {
                        Tabulatorausrichtung = 
                            tab.Alignment == WdTabAlignment.wdAlignTabLeft
                                ? TabulatorAusrichtung.Links 
                                : TabulatorAusrichtung.Rechts,
                        Tabulatorart = TabulatorArt.Tabulator,
                        Position = tab.Position
                    };

                    tabList.Add(t);
                }
            }
        }
        if (!getTabsForCase)
        {
            foreach (TabStop ts in style.ParagraphFormat.TabStops)
            {
                if (ts.CustomTab)
                {
                    bool showTab = true;
                    foreach (TabStop tab in para.TabStops)
                    {
                        if (Math.Abs(tab.Position - ts.Position) > 0.0001 || tab.Alignment != ts.Alignment)
                        {
                            showTab = false;
                            break;
                        }
                    }
                    if (showTab)
                    {
                        Tabulator t = new Tabulator
                        {
                            Tabulatorausrichtung = TabulatorAusrichtung.Geloescht,
                            Tabulatorart = TabulatorArt.Tabulator,
                            Position = ts.Position
                        };
                        tabList.Add(t);
                    }
                }
            }
        }
        if (Math.Abs(para.LeftIndent - style.ParagraphFormat.LeftIndent) > 0.001 || getTabsForCase)
        {
            Tabulator t = new Tabulator
            {
                Tabulatorausrichtung = TabulatorAusrichtung.Links,
                Tabulatorart = TabulatorArt.Einzug,
                Position = para.LeftIndent
            };
            tabList.Add(t);
        }
        if (Math.Abs(para.RightIndent - style.ParagraphFormat.RightIndent) > 0.001 || getTabsForCase)
        {
            Tabulator t = new Tabulator
            {
                Tabulatorausrichtung = TabulatorAusrichtung.Rechts,
                Tabulatorart = TabulatorArt.Einzug,
                Position = para.RightIndent
            };
            tabList.Add(t);
        }
        if (Math.Abs(para.FirstLineIndent - style.ParagraphFormat.FirstLineIndent) > 0.001 || getTabsForCase)
        {
            Tabulator t = new Tabulator
            {
                Tabulatorausrichtung = TabulatorAusrichtung.ErstzeilenEinzug,
                Tabulatorart = TabulatorArt.Einzug,
                Position = para.FirstLineIndent
            };
            tabList.Add(t);
        }
    }

    public class Tabulator
    {
        private TabulatorArt m_Tabulatorart;
        private TabulatorAusrichtung m_Tabulatorausrichtung;
        private float m_Position;
        private bool m_UebernahmeInFolgedokument = false;

        public float Position
        {
            get { return m_Position; }
            set { m_Position = value; }
        }

        public float PositionOrg
        {
            get;
            set;
        }

        public float PositionInCm
        {
            get
            {
                return (m_Position / 28.35F);
            }
            set
            {
                m_Position = value * 28.35F;
            }
        }

        public TabulatorArt Tabulatorart
        {
            get { return m_Tabulatorart; }
            set { m_Tabulatorart = value; }
        }

        public TabulatorAusrichtung Tabulatorausrichtung
        {
            get { return m_Tabulatorausrichtung; }
            set { m_Tabulatorausrichtung = value; }
        }

        public TabulatorAusrichtung TabulatorausrichtungOrg
        {
            get;
            set;
        }


        public bool UebernahmeInFolgedokument
        {
            get { return m_UebernahmeInFolgedokument; }
            set { m_UebernahmeInFolgedokument = value; }
        }
    }

    public enum TabulatorArt
    {
        Invalid = 0,
        Tabulator = 1,
        Einzug = 2
    }

    public enum TabulatorAusrichtung
    {
        Invalid = 0,
        Links = 1,
        Rechts = 2,
        ErstzeilenEinzug = 3,
        Geloescht = 4,
    }
}

在这两个程序中,我加载了一个应用程序,打开一个包含几个段落和选项卡的文档,然后为每个段落运行这个方法,如下所示:

    private void TestSlowMethod(Word.Document document)
    {
        Word.Paragraphs documentParagraphs = document.Paragraphs;
        List<Tabulator> tabList = new List<Tabulator>();
        long swElapsedMilliseconds = 0;
        foreach (Word.Paragraph documentParagraph in documentParagraphs)
        {
            Word.Style style = documentParagraph.get_Style();

            Stopwatch sw = new Stopwatch();
            sw.Start();

            SlowExample.GetTabsFromParagraph(documentParagraph, style, tabList, true);

            sw.Stop();
            swElapsedMilliseconds += sw.ElapsedMilliseconds;
            Debug.WriteLine(sw.ElapsedMilliseconds + "\r\n");
        }

        MessageBox.Show("Total ms: " + swElapsedMilliseconds);
        Debug.WriteLine("Done...");
    }

我发现插件的运行速度提高了 10-20 倍。

  • 插件:每次调用 20-30 毫秒
  • WinForms 工具:每次调用 200-300 毫秒

这是为什么呢?我的假设是,插件在与单词应用程序相同的上下文/进程中运行。但这是真正的原因吗?

我们可以解决这个问题吗?我们的软件从插件转移到 WPF + Interop-Word。

提前致谢!

【问题讨论】:

  • 什么样的插件(使用什么技术)?
  • 插件正在使用 VSTO 模板。 (Word 2013 和 2016 VSTO 插件)
  • 您设置对 PIA 的引用有什么不同吗?是否都为每个 PIA 使用相同的嵌入互操作类型属性设置?但是,是的,因为 VSTO 是由 Word 进程加载的,所以它会更快一些,尽管永远不会像 VBA(在进程中运行)那样快。如果性能至关重要,您最好将内容作为 WordOpenXML 获取并“解析”,因为这将在 Word 进程之外以 .NET Framework 速度运行。
  • 有没有办法让一些代码在 VSTO 插件中运行?我通过覆盖受保护的覆盖对象 RequestComAddInAutomationService() 方法进行了尝试。调用执行成功,可惜还是很慢……是要切换线程还是为什么还是很慢?我尝试使用我在 ThisAddIn_Startup 中设置的类“SynchronizationContext”,但该方法仍然很慢,即使在 Context.Send(o => { // Here's the slow code }, null)
  • 恐怕我不知道您要做什么以及它对速度的影响。但毫无疑问,最快的方法是分析 Document.Content.WordOpenXML 而不是遍历 Word 对象。

标签: c# performance office-interop word-addins


【解决方案1】:

一些性能修复:

在这里尽快检查getTabsForCase

    if (tab.CustomTab)
    {
        bool showTab = true;

        if (getTabsForCase) //insert this here, no need to run if getTabsForCase.
            foreach (TabStop ts in style.ParagraphFormat.TabStops)
            {
                if (Math.Abs(ts.Position - tab.Position) < 0.001 &&
                    ts.Alignment == tab.Alignment)
                {
                    showTab = false;
                    break;
                }
            }
        if (showTab || getTabsForCase)
        {
            Tabulator t = new Tabulator
            {
                Tabulatorausrichtung = 
                    tab.Alignment == WdTabAlignment.wdAlignTabLeft
                        ? TabulatorAusrichtung.Links 
                        : TabulatorAusrichtung.Rechts,
                Tabulatorart = TabulatorArt.Tabulator,
                Position = tab.Position
            };

            tabList.Add(t);
        }
    }

同样,在 if 语句中的所有计算之前检查 getTabsForCase

//see getTabsForCase goes first
if (getTabsForCase || Math.Abs(para.LeftIndent - style.ParagraphFormat.LeftIndent) > 0.001)

先修复所有这些条件以使用getTabsForCase - 然后语句的其余部分就不需要计算了。

【讨论】:

  • 在我们的特殊情况下,标志始终为真(参见调用)。确实,您应该确定要进行修复,但不幸的是,在这种特殊情况下修复不会做任何事情:)
猜你喜欢
  • 2012-07-08
  • 2014-03-12
  • 2021-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-01
  • 2010-12-09
  • 1970-01-01
相关资源
最近更新 更多