我试图避免计算字符串并将其传递给单独的静态类,如果该类中设置的标志无论如何都会跳过使用字符串的话.用System.Diagnostics.Stopwatch
进行基本性能测量.一个C#.NET框架4.8库,它是语音识别应用程序的插件.
该插件对一个静态类进行多次调用,传递各种求值字符串.根据该类中设置的静态状态过滤不同的调用,因此仅当匹配的静态布尔值为真时才使用字符串.例如
只有当Logger.MenuItems
为真时,Logger.MenuWrite(string msg)
才会记录该字符串.
从秒表度量来看,我认为无论Logger类是否不会使用字符串,都会对它们进行计算(也就是说,我不认为JIT没有内联).虽然这对性能的影响很小,但我正在try 在扩展它的过程中尽可能地获得每一毫秒.
到目前为止,我try 和测试的内容如下:
我在一些循环周围添加了秒表测量,这些循环在Logger.MenuItems
为假的情况下进行了大量的Logger.MenuWrite()
次调用,然后使用Check for Logger.MenuItems对每个调用进行了内联,并看到了明确的、可重复的差异-使用只有一个求值字段的字符串,每Logger.MenuWrite()
0次调用大约减少一毫秒.
我首先在Logger类中的静态方法上try 了[MethodImpl(MethodImplOptions.AggressiveInlining)]
,如下所示:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MenuWrite(string msg)
{
if (s_MenuItems )
{ vaProxy.WriteToLog(s_Prefix + msg); }
}
这将循环的时间减少了一半,但这仍然比我在循环中进行实际直接判断多出约1/2毫秒,例如:
if (Logger.MenuItems) { Logger.MenuWrite(msg); }
个
所以我try 使用Delegates,如下所示:
static Action<string> LogIfMenu = (msg) =>
{
if (Logger.MenuItems) { Logger.MenuWrite(msg); }
};
但使用LogIfMenu
呼叫的性能似乎与使用[MethodImpl(MethodImplOptions.AggressiveInlining)]
的性能相同或更差.
有没有想过是什么原因导致了Perf命中-字符串求值/创建、方法调用,或者其他什么?我会感激任何建议或 Select ,除了手动内联所有的呼叫.谢谢.
编辑:
- 通过计算字符串,我的意思是拉入其他数据,如:
$"Passed: {Cmd.Observable} and {Cmd.Dist}"
- 我将try 查看列出的其他Perf工具,但确实需要测量发布版本中所用的时间
- 恐怕我必须使用动态对象来记录日志(log),因为这是我的插件所提供的应用程序.也就是说,我不认为这是这个问题的一部分,所以从代码片段中删除了它.
编辑:将可重现的小示例修改为控制台应用程序.
// File1.cs
namespace CS_Console_Test_05
{
static public class Logger
{
public static bool MenuItems = false;
public static void MenuWrite(string msg)
{
if (MenuItems) { Console.WriteLine(msg); }
}
}
}
// File2.cs
namespace CS_Console_Test_05
{
internal class Program
{
public static void LoopMessagesInline()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
if (Logger.MenuItems)
{ Logger.MenuWrite($"Counting Down to the time {sw.Elapsed}"); }
}
sw.Stop();
Console.WriteLine($"Inline Elapsed = {sw.Elapsed}");
}
public static void LoopMessagesCall()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
Logger.MenuWrite($"Counting Down to the time {sw.Elapsed}");
}
sw.Stop();
Console.WriteLine($"Called Elapsed = {sw.Elapsed}");
}
static void Main(string[] args)
{
do
{
Console.WriteLine("Enter Value for MenuItems:");
string miRead = Console.ReadLine();
Logger.MenuItems = (miRead.Equals("Kludge")); // so JIT won't know if true or false
Console.WriteLine("'x' to quit, SPACE for Inline, nothing for Call, then ENTER: ");
string way = Console.ReadLine();
way = way.ToLower();
if (way.Equals(" "))
{ LoopMessagesCall(); }
else if (way.Equals("x"))
{ return; }
else
{ LoopMessagesInline(); }
} while (true);
}
}
}
调用LoopMessageInline()大约需要7-8毫秒.调用LoopMessageCall()所需时间不到1毫秒.
如上所述,无论是MethodImplOptions.AggressiveInlining还是使用Delegates似乎都无济于事.