- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用ReadOnlySpan
,我想亲自看看它比使用字符串快得多,但是......到目前为止,情况并非如此。我知道我的代码中可能犯了一个错误,但我找不到它。
static int CountCharacterWithoutSpan(string originalString, string sequence)
{
int count = 0;
for (int i = 0, length = originalString.Length - sequence.Length; i < length; ++i)
{
if (originalString.Substring(i, sequence.Length).Equals(sequence))
{
count++;
}
}
return count;
}
static int CountCharacterWithSpan(ReadOnlySpan<char> originalString, string sequence)
{
int count = 0;
for (int i = 0, length = originalString.Length - sequence.Length; i < length; ++i)
{
if (originalString.Slice(i, sequence.Length).SequenceEqual(sequence))
{
count++;
}
}
return count;
}
基本上,这段代码的目标是能够在另一个字符串中找到一个字符串。两者之间的区别在于我使用 Slice
而不是 Substring
和 SequenceEqual
而不是 Equals
。但是,当我使用 Stopwatch 运行和监视此代码时,CountCharacterWithSpan 总是比 CountCharacterWithoutSpan 多花费 2 到 3 倍(字符串测试是约 80K 字符)。
我认为问题来自 SequenceEquals
但这是我发现比较切片 ReadOnlySpan
和常规字符串的唯一方法(Equals
确实不起作用,==
更快,但比较引用,所以结果不正确)
最佳答案
与您在问题中所说的相反,基于跨度的版本实际上比非基于跨度的版本快得多。
根据 morten-mertner 在评论中的建议,我对你的第二种方法做了一个稍微修改的版本:
public static int CountCharacterWithSpan(
ReadOnlySpan<char> originalString, ReadOnlySpan<char> sequence)
{
int count = 0;
for (int i = 0, length = originalString.Length - sequence.Length; i < length; ++i)
{
if (originalString.Slice(i, sequence.Length).SequenceEqual(sequence))
{
count++;
}
}
return count;
}
但正如我们将看到的,这没有什么区别。它与您最初的基于跨度的速度大约一样快,并且都比您的非基于跨度的速度快得多。
这是 BenchmarkDotNet 报告的所有三个内容,使用 80K 字符 originalString
,以及 20 个字符 sequence
在 .NET Core 2.2 上运行,每个版本都有三个变体。在“随机”变体中,sequence
只是随机文本,因此可以很早就检测到不存在匹配项。在“匹配”变体中,sequence
是一个确实存在于文本中某处的子字符串,但输入仍然是随机的,因此大多数搜索很快就会终止,但有一个会很慢。在“MatchAll”情况下,originalString
和sequence
一遍又一遍地都是同一个字符,这意味着每次比较都会成功,这意味着尽可能多的比较工作。 (它需要一遍又一遍地比较每个字符。)
| Method | Mean | Error | StdDev |
|---------------------------- |-----------:|-----------:|-----------:|
| OriginalWithoutSpanRandom | 1,087.1 us | 11.4152 us | 10.6778 us |
| OriginalWithoutSpanMatch | 1,098.8 us | 26.0405 us | 23.0842 us |
| OriginalWithoutSpanMatchAll | 1,164.3 us | 15.8291 us | 14.8066 us |
| OriginalWithSpanRandom | 188.8 us | 1.3194 us | 1.2341 us |
| OriginalWithSpanMatch | 188.3 us | 0.6132 us | 0.5736 us |
| OriginalWithSpanMatchAll | 224.3 us | 3.0027 us | 2.8087 us |
| ModifiedWithSpanRandom | 189.0 us | 0.9979 us | 0.9334 us |
| ModifiedWithSpanMatch | 189.5 us | 1.1694 us | 1.0367 us |
| ModifiedWithSpanMatchAll | 223.2 us | 1.3251 us | 1.2395 us |
以下是更改的结果sequence
为 200 个字符:
| Method | Mean | Error | StdDev |
|---------------------------- |-----------:|----------:|----------:|
| OriginalWithoutSpanRandom | 2,432.2 us | 35.777 us | 31.715 us |
| OriginalWithoutSpanMatch | 2,476.1 us | 42.809 us | 35.747 us |
| OriginalWithoutSpanMatchAll | 2,815.6 us | 22.508 us | 19.953 us |
| OriginalWithSpanRandom | 190.2 us | 1.531 us | 1.432 us |
| OriginalWithSpanMatch | 189.8 us | 1.937 us | 1.717 us |
| OriginalWithSpanMatchAll | 602.3 us | 4.662 us | 4.361 us |
| ModifiedWithSpanRandom | 190.1 us | 2.200 us | 2.058 us |
| ModifiedWithSpanMatch | 191.1 us | 2.860 us | 2.675 us |
| ModifiedWithSpanMatchAll | 599.9 us | 3.696 us | 3.457 us |
如果我们改变sequence
,它会是什么样子? 2000 个字符:
| Method | Mean | Error | StdDev |
|---------------------------- |------------:|-----------:|-----------:|
| OriginalWithoutSpanRandom | 16,819.9 us | 310.576 us | 290.513 us |
| OriginalWithoutSpanMatch | 17,148.8 us | 231.140 us | 216.209 us |
| OriginalWithoutSpanMatchAll | 21,817.9 us | 246.378 us | 218.408 us |
| OriginalWithSpanRandom | 184.2 us | 1.633 us | 1.528 us |
| OriginalWithSpanMatch | 185.3 us | 1.440 us | 1.347 us |
| OriginalWithSpanMatchAll | 4,649.7 us | 22.810 us | 20.221 us |
| ModifiedWithSpanRandom | 185.2 us | 1.198 us | 1.120 us |
| ModifiedWithSpanMatch | 186.7 us | 2.158 us | 2.019 us |
| ModifiedWithSpanMatchAll | 4,651.1 us | 25.013 us | 22.173 us |
正如您所看到的,我无法重现您所描述的结果,其中“CountCharacterWithSpan
总是比 CountCharacterWithoutSpan
多花 2 到 3 倍”。在这些测试中,CountCharacterWithoutSpan
始终比 ReadOnlySpan<char>
中的任何一个慢得多基于版本。 (但这两者之间的差异太小,无法衡量。)
对于这两种基于跨度的方法,每次比较中完成的工作量都是巨大的:您可以看到测试之间存在显着差异,其中大多数字符串比较可以在一个或两个字符后退出,而测试则在它必须比较每个字符。 (不过,Random
和 Match
示例之间没有任何有意义的区别 - 似乎让所有比较提前退出和让一个提前退出的成本差异很小。这并不奇怪,因为我们基本上看看 80,000 个比较中的一个是昂贵的,其余的是便宜的。
这里绝对清楚的是,非基于跨度的版本很昂贵。调用Substring
那会杀死它。这在大多数比较几乎立即失败的测试中尤其糟糕:您分配了 originalString
的某些子字符串的 2,000 个字符副本。 ,然后只看少数几个字符。
请注意,在我们能够提前退出的情况下,基于跨度的版本的性能几乎与 sequence
的长度无关。 - 所有情况下大约 190us。这就是您所希望的 - 如果我们可以很早就确定没有匹配项,那么多久并不重要 sequence
是,但在非基于跨度的版本中, sequence
的长度即使在这些情况下也很重要。
您在测试中进行了多少次测量?我想知道您是否只是测量一次运行,在这种情况下,您并没有真正测量代码运行所需的时间:您主要是测量 JIT 编译器编译它需要多长时间。
关于c# - 为什么我的 ReadOnlySpan<char> 比我的字符串慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50883983/
呃......微软已经做了一些事情。 过去几个小时(大约 10:00 GMT)启动的所有构建都因以下错误(来自日志)而因“构建解决方案步骤”而失败: ##[error]EXEC(0,0): Error
我尝试理解 .net core 3.0。据我所知,我不能将 Span 或 ReadonlySpan 用作属性或成员,因为它是基于堆栈的结构。我想知道以下定义之间的区别。我可以成功定义“part1”而不
好的,.NET Core 2.1 已经落地。有了它,我们就得到了一种处理字符串数据的新方法 ReadOnlySpan 。它非常适合分割字符串数据,但是如何将跨度重新组合在一起呢? var hello
以下代码会导致编译器在属性 getter 的第一行抛出错误 CS1605(“无法将 'var' 作为 ref 或 out 参数传递,因为它是只读的”)。 [StructLayout(LayoutKin
我有一个相当简单的字符串扩展方法,该方法在我拥有的系统中被频繁调用,该方法正在执行大量字符串操作。我读了这篇文章 ( String.Substring() seems to bottleneck th
我正在使用ReadOnlySpan,我想亲自看看它比使用字符串快得多,但是......到目前为止,情况并非如此。我知道我的代码中可能犯了一个错误,但我找不到它。 static int CountCha
ReadOnlySpan据说非常适合解析,所以我尝试使用它,但遇到了一个我不知道如何处理的用例。 我有一个命令行 string其中参数前缀 -和分隔符 (空格)被转义了(我知道我可以在这里引用它们但是
引入了 C# 7.2 reference semantics with value-types ,除此之外,微软还开发了类似 Span and ReadOnlySpan 的类型潜在地提高需要在连续内存
假设我有如下方法: unsafe void Convert(byte* ptr, int length) { var span = new Span(ptr, length); var
在解析 int 时数据来自 string , 有没有办法使用 ReadOnlySpan ?喜欢int.Parse(str.AsSpan().Slice(2,3)) 因为如果 int 数据在字符串的中间
我理解为什么 ReadOnlySpan 不能用作泛型类的类型参数。 ReadOnlySpan 只是堆栈,因此它不能用作字段类型,字段成员像它的容器对象一样存在于堆中。然而,返回值和参数始终只是堆栈,那
我的类(class)有一个属性 public byte[] Location{get;} = new byte[30];我希望能够从 ReadOnlySpan 填充它但我找不到任何允许这样做的 API
Microsoft 在 Write safe and efficient C# code 中推荐: Apply the in modifier to readonly struct parameter
如果我已经只有 ReadOnlySpan 切片,那么连接字符串的最有效方法是什么? 简化示例: public class Program { public string ConcatSpans
我正在尝试尽可能快地解析二进制文件。所以这是我第一次尝试做的: using (FileStream filestream = path.OpenRead()) { using (var d =
我想知道当两者都ReadOnlySpan时是否有任何界面、模式或其他什么东西和 IReadOnlyList (以及更通用的接口(interface)),并且您希望避免无用的分配 . 考虑使用 IEnu
我正在寻找一种高效、免分配(!)的实现 public static int IndexOf(this ReadOnlySpan utf8Bytes, char @char) { // Shoul
我正在 Fsharp 中创建 RSA pki 并尝试加载私钥: let getRsa () = let rsa = RSA.Create() let privateKey = ge
我正在 Fsharp 中创建 RSA pki 并尝试加载私钥: let getRsa () = let rsa = RSA.Create() let privateKey = ge
我使用的是 Visual Studio 15.5.6 版本。 当我创建一个简单的控制台应用程序项目时,我无法使用 ReadOnlySpan或 Span或 Memory . 我将项目设置为 .Net F
我是一名优秀的程序员,十分优秀!