- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图避免评估字符串并将其传递给单独的静态类,如果该类中设置的标志无论如何都会跳过使用字符串。使用 System.Diagnostics.Stopwatch 进行基本性能测量。一个 C# .NET Framework 4.8 库,它是语音识别应用程序的插件。
该插件多次调用静态类,传递各种评估的字符串。根据该类中设置的静态状态过滤不同的调用,因此仅当匹配的静态 bool 值为 true 时才使用字符串。例如
Logger.MenuWrite(string msg)
仅当 Logger.MenuItems
为 true 时才会记录字符串。
根据秒表测量,我认为无论 Logger 类是否不会使用字符串,字符串总是会被评估(也就是说,我不认为 JIT 不是内联的)。虽然这样做的性能影响很小,但我在扩大规模时会尽力争取每一毫秒。
到目前为止我已经尝试和测试过的内容:
我在一些循环周围添加了秒表测量,这些循环在 Logger.MenuItems
为 false 时进行了大量 Logger.MenuWrite()
调用,然后使用检查测量了相同的循环对于 Logger.MenuItems,每次调用都是内联完成的,并且看到了明确的、可重复的差异 - 对于只有一个评估字段的字符串,每 1000 次调用会减少大约一毫秒。
我首先在 Logger 类中的静态方法上尝试了 [MethodImpl(MethodImplOptions.AggressiveInlined)]
,如下所示:
[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); }
所以我尝试使用委托(delegate),如下所示:
static Action<string> LogIfMenu = (msg) =>
{
if (Logger.MenuItems) { Logger.MenuWrite(msg); }
};
但是使用 LogIfMenu
调用似乎与使用 [MethodImpl(MethodImplOptions.AggressiveInlined)]
具有相同或更差的性能。
对于导致性能命中的原因有什么想法 - 字符串评估/创建、方法调用,还是其他什么?除了手动内联所有调用之外,将不胜感激任何建议或选项。谢谢。
编辑:
$"Passed: {Cmd.Observable} and {Cmd.Dist}"
编辑:将小型可重现示例修改为控制台应用程序。
// 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.AggressiveInlined 和使用 Delegates 似乎都无济于事。
最佳答案
首先使用适当的基准测试工具 - 例如 BenchmarkDotNet .
我提出了以下基准:
namespace CS_Console_Test_05
{
static public class Logger
{
public static bool MenuItems = false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MenuWrite(string msg)
{
if (MenuItems)
{
Console.WriteLine(msg);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MenuWriteFormattableString(FormattableString msg)
{
if (MenuItems)
{
Console.WriteLine(msg);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MenuWriteFunc(Func<string> msg)
{
if (MenuItems)
{
Console.WriteLine(msg());
}
}
}
}
[MemoryDiagnoser]
public class LoggerWrapperBench
{
public static string Value = "TestVal";
private const int Iterations = 1000;
[Benchmark]
public void LoopMessagesInline()
{
for (int i = 0; i < Iterations; i++)
{
if (Logger.MenuItems)
{
Console.WriteLine($"Counting Down to the time {Value}");
}
}
}
[Benchmark]
public void LoopMessagesInlineFormatableString()
{
for (int i = 0; i < Iterations; i++)
{
Logger.MenuWriteFormattableString($"Counting Down to the time {Value}");
}
}
[Benchmark]
public void LoopMessagesInlineFunc()
{
for (int i = 0; i < Iterations; i++)
{
Logger.MenuWriteFunc(() => $"Counting Down to the time {Value}");
}
}
[Benchmark]
public void LoopMessagesCall()
{
for (int i = 0; i < Iterations; i++)
{
Logger.MenuWrite($"Counting Down to the time {Value}");
}
}
}
这在我的机器上给出:
使惰性函数方法最接近内联方法(尽管我有点想知道为什么它不分配任何东西)。
请注意,在 MenuWrite
的情况下,内联对字符串计算没有太大影响。和MenuWriteFormattableString
因为:
var s = DoSomething(); // like build string
if(...)
{
Console.WriteLine(s);
}
还有
if(...)
{
Console.WriteLine(DoSomething());
}
在一般情况下功能并不等效(由于函数调用可能产生副作用),因此内联不应改变程序的正确性,因此会调用字符串格式化(至少这是我关于该主题的理论)。
UPD
还有一种方法值得一提(尽管我无法让它执行得更快,并且在多个插值元素的情况下甚至可以执行得更慢) - 从 .NET 6 开始,您可以创建一个 custom interpolated string handler :
[InterpolatedStringHandler]
public readonly ref struct LogInterpolatedStringHandler
{
readonly StringBuilder? _builder;
public LogInterpolatedStringHandler(int literalLength, int formattedCount)
{
if (Logger.MenuItems)
{
_builder = new StringBuilder(literalLength);
}
}
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t?.ToString());
internal string GetFormattedText()
{
if (_builder is not null)
{
var format = _builder.ToString();
Console.WriteLine(format);
return format;
}
return string.Empty;
}
}
及用法:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void MenuWriteInterpolatedStringHandler(ref LogInterpolatedStringHandler msg)
{
if(MenuItems) msg.GetFormattedText();
}
[Benchmark]
public void LoopMenuWriteInterpolatedStringHandler()
{
for (int i = 0; i < Iterations; i++)
{
Logger.MenuWriteInterpolatedStringHandler($"Counting Down to the time {Value}");
}
}
这在我的机器上给出:
关于c# - Lambda Actions 或 AggressiveInlined 以避免评估复杂的字符串并将其传递给单独的静态类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75961411/
可以使用 lambda 和函数创建有序对(Lisp 中的缺点),如 Use of lambda for cons/car/cdr definition in SICP 所示。 它也适用于 Python
我正在尝试从另一个调用一个 AWS lambda 并执行 lambda 链接。这样做的理由是 AWS 不提供来自同一个 S3 存储桶的多个触发器。 我创建了一个带有 s3 触发器的 lambda。第一
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。 fun main(args: Array) { val numbers = listOf(1, 2, 3) f
A Tutorial Introduction to the Lambda Calculus 本文介绍乘法函数 The multiplication of two numbers x and y ca
我想弄清楚如何为下面的表达式绘制语法树。首先,这究竟是如何表现的?看样子是以1和2为参数,如果n是 0,它只会返回 m . 另外,有人可以指出解析树的开始,还是一个例子?我一直找不到一个。 最佳答案
在 C++0x 中,我想知道 lambda 函数的类型是什么。具体来说: #include type1 foo(int x){ return [x](int y)->int{return x * y
我在其中一个职位发布中看到了这个问题,它询问什么是 lambda 函数以及它与高阶函数的关系。我已经知道如何使用 lambda 函数,但不太自信地解释它,所以我做了一点谷歌搜索,发现了这个:What
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
我正在处理 MyCustomType 的实例集合如下: fun runAll(vararg commands: MyCustomType){ commands.forEach { it.myM
Brian 在他对问题 "Are side effects a good thing?" 的论证中的前提很有趣: computers are von-Neumann machines that are
在 Common Lisp 中,如果我希望两个函数共享状态,我将按如下方式执行 let over lambda: (let ((state 1)) (defun inc-state () (in
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
作为lambda calculus wiki说: There are several possible ways to define the natural numbers in lambda cal
我有一个数据类,我需要初始化一些 List .我需要获取 JsonArray 的值(我使用的是 Gson)。 我做了这个函数: private fun arrayToList(data: JsonAr
((lambda () )) 的方案中是否有简写 例如,代替 ((lambda () (define x 1) (display x))) 我希望能够做类似的事情 (empty-lam
我在 Java library 中有以下方法: public void setColumnComparator(final int columnIndex, final Comparator colu
我正在研究一个函数来计算国际象棋游戏中棋子的有效移动。 white-pawn-move 函数有效。当我试图将其概括为任一玩家的棋子 (pawn-move) 时,我遇到了非法函数调用。我已经在 repl
考虑这段代码(在 GCC 和 MSVC 上编译): int main() { auto foo = [](auto p){ typedef decltype(p) p_t;
我正在阅读一个在 lambda 内部使用 lambda 的片段,然后我想通过创建一个虚拟函数来测试它,该函数从文件中读取然后返回最大和最小数字。 这是我想出来的 dummy = lambda path
我是一名优秀的程序员,十分优秀!