前言
前一段时间,接到一个需求,就是对接钉钉打卡,获取钉钉打卡数据,要先进行注册钉钉打卡事件,然后对钉钉推送的数据进行解密.然后将数据加密后返回给钉钉.这里忍不住要吐槽一下钉钉给数据加解密的Demo(在Github上开源的)有点不专业的了,这里主要说提供C#示例代码,文档注释是使用Java的,算了,在这里不是重点,说回Linq下Take方法.C#示例代码在加解密用到了Take方法.如果需要性能要求高的话,使用Take还是要稍微慎重一下.
RijndaelManaged rDel = new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.Zeros,
Key = aesKey,
IV = aesKey.ToList().Take(16).ToArray() //使用Take取16个元素
};
Take是可以进行优化的.
var arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var a1 = arr.Take(3); //取前3个元素
//?? 在.Net Core及之后的版本可以使用下面的代码进行优化
var a2 = arr.AsSpan().Slice(0, 3);
如果不知道Span的话,可以看看 在.Net Core中使用Span
可以看到asSpan后Slice没有重新分配一个数组.
性能测试
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
namespace net6perf.LinqTest
{
[DisassemblyDiagnoser(printSource: true, maxDepth: 2)]
[MemoryDiagnoser]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class TakTest
{
public int[] bytes = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 48, 98, 10 };
[Params(1024, 2048)]
public int Times { get; set; }
[Benchmark]
public int Take()
{
int sum = 0;
for (int i = 0; i < Times; i++)
{
var array = bytes.Take(5).ToArray();
sum += array.Length;
}
return sum;
}
[Benchmark]
public int AsSpan()
{
int sum = 0;
for (int i = 0; i < Times; i++)
{
var array = bytes.AsSpan().Slice(0, 5);
sum += array.Length;
}
return sum;
}
}
}
根据测试结果:发现Take和Slice性能不在一个级别.下面看一下Take源码:
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
return count <= 0 ?
Empty<TSource>() :
TakeIterator<TSource>(source, count);
}
private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
Debug.Assert(count > 0);
foreach (TSource element in source)
{
yield return element; //yield简化迭代器,具体可以使用ILSpy工具反编译,查看生成IL代码
if (--count == 0) break;
}
}
个人能力有限,如果您发现有什么不对,请私信我
如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流
本文暂时没有评论,来添加一个吧(●'◡'●)