【发布时间】: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