编译器使用经典交换对字符串反向方法进行了哪些优化?(What optimization is the compiler doing for my string reverse method with

编程入门 行业动态 更新时间:2024-10-21 16:34:40
编译器使用经典交换对字符串反向方法进行了哪些优化?(What optimization is the compiler doing for my string reverse method with a classic swapping?)

问题背景

我读到了这个问题,即如何尽可能快地反转字符串。 我发现其中一个答案是比较不同的方法。 在其中的一个中,他们只是从位置i运行一个循环交换元素,位置是string.Length-1-i但他们通过XOR使用已知的棘手交换。 我想知道使用通过XOR交换的字符串反转速度与使用经典交换通过时间变量的相同方法相比有多快。 令人惊讶的是,我比XOR获得了近50%的提升。

问题

编译器在幕后做了些神奇的事情,为什么我会得到这个结果?

修改后的代码与基准

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ContestLibrary { public class Problem { delegate string StringDelegate(string s); static void Benchmark(string description, StringDelegate d, int times, string text) { Stopwatch sw = new Stopwatch(); sw.Start(); for (int j = 0; j < times; j++) { d(text); } sw.Stop(); Console.WriteLine("{0} Ticks {1} : called {2} times.", sw.ElapsedTicks, description, times); } public static string ReverseXor(string s) { char[] charArray = s.ToCharArray(); int len = s.Length - 1; for (int i = 0; i < len; i++, len--) { charArray[i] ^= charArray[len]; charArray[len] ^= charArray[i]; charArray[i] ^= charArray[len]; } return new string(charArray); } public static string ReverseClassic(string s) { char[] charArray = s.ToCharArray(); int len = s.Length-1; for (int i = 0; i < len; i++, len--) { char temp = charArray[len]; charArray[len] = charArray[i]; charArray[i] = temp; } return new string(charArray); } public static string StringOfLength(int length) { Random random = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)))); } return sb.ToString(); } static void Main(string[] args) { int[] lengths = new int[] {1,10,100,1000, 10000, 100000}; foreach (int l in lengths) { int iterations = 10000; string text = StringOfLength(l); Benchmark(String.Format("Classic (Length: {0})", l), ReverseClassic, iterations, text); Benchmark(String.Format("Xor (Length: {0})", l), ReverseXor, iterations, text); Console.WriteLine(); } Console.Read(); } } }

Question Background

I read this question that is about how to reverse a string as fast as possible. I found that one of the answers was comparing different methods. In one of them, they just run a loop swapping elements from position i with the one at position string.Length-1-i but they use the known tricky swap via XOR. I was wondering how faster is reversing the string using the swap via XOR in comparison with the same method using the classic swap via a temporal variable. Surprisingly I'm getting almost a 50% improvement over the XOR one.

The Question

Is the compiler doing something magic behind the scenes, why I'm I getting this result?

The modified code with the Benchmarks

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ContestLibrary { public class Problem { delegate string StringDelegate(string s); static void Benchmark(string description, StringDelegate d, int times, string text) { Stopwatch sw = new Stopwatch(); sw.Start(); for (int j = 0; j < times; j++) { d(text); } sw.Stop(); Console.WriteLine("{0} Ticks {1} : called {2} times.", sw.ElapsedTicks, description, times); } public static string ReverseXor(string s) { char[] charArray = s.ToCharArray(); int len = s.Length - 1; for (int i = 0; i < len; i++, len--) { charArray[i] ^= charArray[len]; charArray[len] ^= charArray[i]; charArray[i] ^= charArray[len]; } return new string(charArray); } public static string ReverseClassic(string s) { char[] charArray = s.ToCharArray(); int len = s.Length-1; for (int i = 0; i < len; i++, len--) { char temp = charArray[len]; charArray[len] = charArray[i]; charArray[i] = temp; } return new string(charArray); } public static string StringOfLength(int length) { Random random = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)))); } return sb.ToString(); } static void Main(string[] args) { int[] lengths = new int[] {1,10,100,1000, 10000, 100000}; foreach (int l in lengths) { int iterations = 10000; string text = StringOfLength(l); Benchmark(String.Format("Classic (Length: {0})", l), ReverseClassic, iterations, text); Benchmark(String.Format("Xor (Length: {0})", l), ReverseXor, iterations, text); Console.WriteLine(); } Console.Read(); } } }

最满意答案

原因很简单,我们来检查每个函数在IL代码中有多少操作。 但首先,让我们看看两个功能的真正时间差异。 你说XOR函数比另一个慢了50%,当我在Debug模式下运行代码时,我得到了这个结果,但是你必须在Release模式下运行代码才能完全允许优化器完成它的工作:)。 在释放模式下,XOR功能几乎慢了3倍。

图片包含for循环内部分的IL代码,这是唯一改变的部分。

第一张图是带有temp变量的函数

带有temp变量的经典代码

第二张图是具有XOR的功能

XOR功能

正如您所看到的,指令数量的差异是巨大的,14对34。时间差异的3倍来自一些像conv.u2这样有点贵的操作。

The reason is very simple, lets check how many operations in IL code each function has. But first, lets see the real difference in time of both functions. You said that the XOR function is almost 50% slower than the other, when I run the code in Debug mode I have that results, but you must run the code in Release mode to fully allow the optimizer do its job :). In release mode the XOR functions is almost 3x slower.

The pictures have the IL code of the part inside the for loop, that is the only piece that changes.

The first picture is the function with the temp variable

Classic code with the temp variable

The second picture is the function with the XOR

XOR function

As you can see the difference in the number of instructions is huge, 14 against 34. The 3x difference in time come from some operations like conv.u2 that are a little expensive.

更多推荐

本文发布于:2023-07-31 00:39:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1340526.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:编译器   字符串   进行了   方法   经典

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!