首页 > 大数据 > Spark > DBShadow和Dapper对比一下
await using var conn = _dataSource.CreateConnection(); var sql = "SELECT \"Id\",\"Title\",\"Content\",\"Done\",\"LastTime\" FROM \"Todo\" WHERE \"Id\"=@Id" ; var first = await conn.QueryFirstOrDefaultAsync<Todo>(sql, _todo);
ShadowExecutor _executor = ShadowBuilder.CreateCache(engine, Mapper.Default); TodoTable _table = new ( "Todo" ); ISelect _shadowSelect = _table.ToQuery() .And(_table.Id.Equal()) .ToSelect() .SelectSelfColumns();
await using var conn = _dataSource.CreateConnection(); var sql = "SELECT `Id`,`Title`,`Content`,`Done`,`LastTime` FROM `Todo` WHERE `Id`=@Id" ; var first = await conn.QueryFirstOrDefaultAsync<Todo>(sql, _todo);
ISqlEngine engine = new MySqlEngine(); ShadowCachedBuilder _executor = ShadowBuilder.CreateCache(engine, Mapper.Default); TodoTable _table = new ( "Todo" ); ISelect _shadowSelect = _table.ToQuery() .And(_table.Id.Equal()) .ToSelect()
{ await SqliteExecutor.ExecuteAsync(table.ToCreate()); // 建表Accounts } catch { } await new SingleInsert(table) .Insert(table.Id.InsertValue( 1L )) .Insert(table.Amount.InsertValue( 100L )) .ExecuteAsync(SqliteExecutor); // 账号1初始化余额为100 // 查询账号1 var query = table.ToSqlQuery().Where( "Id=1" ); var amount = await query .ToSelect() .Select(account => account.Amount) .GetScalarAsync< long >(SqliteExecutor); // 查询账号1余额为100 Assert.Equal( 100L , amount); // 开启事务 await using var transaction = await SqliteExecutor.BeginTransaction(); { await query.ToUpdate() .Set(account => account.Amount.AssignValue( 90L )) .ExecuteAsync(transaction); // 使用事务把余额设置为90 var amount2 = await query .ToSelect() .Select(account => account.Amount) .GetScalarAsync< long >(transaction); // 在事务下查询余额为90 // 减成了90 Assert.Equal( 90L , amount2); // 事务回滚 await transaction.RollbackAsync(); } var amount3 = await query .ToSelect() .Select(account => account.Amount) .GetScalarAsync< long >(SqliteExecutor);
var table = new AccountTable(); var query = table.ToSqlQuery().Where( "Id=1" ); // 建表预编译 var createCompiled = builder.BuildQuery(table.ToCreate()); // 插入操作预编译 var insertCompiled = builder.BuildQuery( new SingleInsert(table) .Insert(table.Id.InsertValue( 1L )) .Insert(table.Amount.InsertValue( 100L ))); // 查询账号余额预编译 var amountCompiled = builder.BuildScalar(query .ToSelect() .Select(account => account.Amount)); // 修改账号余额预编译 var updateCompiled = builder.BuildQuery(query.ToUpdate() .Set(account => account.Amount.AssignValue( 90L ))); try { await createCompiled.ExecuteAsync(SqliteSource); // 建表Accounts } catch { } await insertCompiled.ExecuteAsync(SqliteSource); // 账号1初始化余额为100 var amount = await amountCompiled.GetScalarAsync< long >(SqliteSource); // 查询账号1余额为100 Assert.Equal( 100L , amount); // 开启事务 await using var transaction = await SqliteSource.BeginTransaction(); { await updateCompiled.ExecuteAsync(transaction); // 使用事务把余额设置为90 var amount2 = await amountCompiled.GetScalarAsync< long >(transaction); // 在事务下查询余额为90 Assert.Equal( 90L , amount2); await transaction.CommitAsync(); // 事务提交 } var amount3 = await amountCompiled.GetScalarAsync< long >(SqliteSource); // 再次查询账号1余额为9
- 数据连接基于System.Data.Common.DbDataSource
- DbDataSource的重要方法CreateConnection
- 相当于数据库连接工厂或连接池
- 虽然微软推出DbDataSource很多年了,但是业界支持的并不是很好
- 比如Sqlite不支持DbDataSource
- 就算是System.Data也只能.net7+才支持
- 这个破破烂烂的世界,需要缝缝补补
- StringDataSource支持net4.5+和netstandard2.0+
- 在.net7+下StringDataSource是DbDataSource的子类
- 其他情况下DBShadow使用StringDataSource直接代替DbDataSource
- 这是异步下的迭代器
- 在异步操作IO流下实现延迟加载和流式计算
- DBShadow的列表都是基于IAsyncEnumerable<>
- EFCore也支持IAsyncEnumerable<>,但Dapper不支持
- 使用ShadowSql拼接sql
- ShadowSql也是笔者的开源项目,之前就有很多相关的介绍
- ShadowSql.net之正确使用方式
- 使用PocoEmit.Mapper来映射
- 把参数映射为SqlParameter
- 把DataReader映射为实体
- 使得DBShadow继承了PocoEmit.Mapper的可配置性、可扩展性和依赖注入等功能,这些EFCore和Dapper都是做不到的
- PocoEmit.Mapper也是笔者的开源项目,之前就有很多相关的介
句话在“大数场景”里基本成立,但
Java BigInteger 同样是不可变类型:
add/multiply/mod/xor/modPow 都会返回新值,业务代码层面你并没有公开的 in-place API 可以复用内部缓冲。
因此,在本文的“主对比”(.NET vs Java)里,双方都在不可变范式下运行,这点是公平的。
\
import
java.util.*;
public
class
BigIntBench
{
// SplitMix64 RNG (deterministic, fast)
static
final
class
SplitMix64
{
private
long
x;
SplitMix64(
long
seed) {
this
.x = seed; }
long
nextLong
()
{
long
z
=
(x +=
0x9E3779B97F4A7C15L
);
z = (z ^ (z >>>
30
)) *
0xBF58476D1CE4E5B9L
;
z = (z ^ (z >>>
27
)) *
0x94D049BB133111EBL
;
return
z ^ (z >>>
31
);
}
void
nextBytes
(
byte[] dst)
{
int
i
=
0
;
while
(i < dst.length) {
long
v
=
nextLong();
for
(
int
k
=
0
; k <
8
&& i < dst.length; k++) {
dst[i++] = (
byte
)(v >>> (
56
-
8
*k));
// big-endian stream
}
}
}
}
static
BigInteger[] genBigInts(
int
bitSize,
int
count,
long
seed) {
SplitMix64
rng
=
new
SplitMix64
(seed);
int
byteLen
=
(bitSize +
7
) /
8
;
BigInteger[] arr =
new
BigInteger
[count];
byte
[] buf =
new
byte
[byteLen];
int
topBit
=
(bitSize -
1
) %
8
;
int
keepBits
=
topBit +
1
;
int
firstMask
=
(keepBits ==
8
) ?
0xFF
: ((
1
<< keepBits) -
1
);
byte
topMask
=
(
byte
)(
1
<< topBit);
for
(
int
i
=
0
; i < count; i++) {
rng.nextBytes(buf);
// Ensure exact bit length:
// - mask away unused top bits when bitSize is not byte-aligned
// - set the top bit so the number has the requested bit length
buf[
0
] &= (
byte
)firstMask;
buf[
0
] |= topMask;
arr[i] =
new
BigInteger
(
1
, buf);
}
return
arr;
}
static
BigInteger
genModulus
(
int bitSize,
long seed)
{
SplitMix64
rng
=
new
SplitMix64
(seed);
int
byteLen
=
(bitSize +
7
) /
8
;
byte
[] buf =
new
byte
[byteLen];
rng.nextBytes(buf);
int
topBit
=
(bitSize -
1
) %
8
;
int
keepBits
=
topBit +
1
;
int
firstMask
=
(keepBits ==
8
) ?
0xFF
: ((
1
<< keepBits) -
1
);
buf[
0
] &= (
byte
)firstMask;
buf[
0
] |= (
byte
)(
1
<< topBit);
buf[buf.length -
1
] |=
1
;
// odd
return
new
BigInteger
(
1
, buf);
}
enum
Op
{ ADD_MOD, MUL_MOD, MODPOW }
static
final
class
Result
{
final
String lang;
final
int
bits;
final
Op op;
final
long
ops;
final
double
nsPerOp;
final
long
checksum;
Result(String lang,
int
bits, Op op,
long
ops,
double
nsPerOp,
long
checksum) {
this
.lang = lang;
this
.bits = bits;
this
.op = op;
this
.ops = ops;
this
.nsPerOp = nsPerOp;
this
.checksum = checksum;
}
String
toJson
()
{
return
String.format(Locale.ROOT,
"{\"lang\":\"%s\",\"bits\":%d,\"op\":\"%s\",\"ops\":%d,\"nsPerOp\":%.3f,\"checksum\":%d}"
,
lang, bits, op.name(), ops, nsPerOp, checksum);
}
}
static
long
runOnce
(Op op, BigInteger[] a, BigInteger[] b, BigInteger[] e, BigInteger mod,
int outer)
{
BigInteger
acc
=
BigInteger.ZERO;
int
n
=
a.length;
switch
(op) {
case
ADD_MOD:
for
(
int
o
=
0
; o < outer; o++) {
for
(
int
i
=
0
; i < n; i++) {
BigInteger
r
=
a[i].add(b[i]).mod(mod);
acc = acc.xor(r);
}
}
break
;
case
MUL_MOD:
for
(
int
o
=
0
; o < outer; o++) {
for
(
int
i
=
0
; i < n; i++) {
BigInteger
r
=
a[i].multiply(b[i]).mod(mod);
acc = acc.xor(r);
}
}
break
;
case
MODPOW:
// here we use a.length as n; e can be same length
for
(
int
o
=
0
; o < outer; o++) {
for
(
int
i
=
0
; i < n; i++) {
BigInteger
r
=
a[i].modPow(e[i], mod);
acc = acc.xor(r);
}
}
break
;
default
:
throw
new
IllegalArgumentException
(
"Unknown op: "
+ op);
}
return
acc.longValue();
}
static
Result
bench
(String lang,
int bits, Op op, BigInteger[] a, BigInteger[] b, BigInteger[] e, BigInteger mod,
long targetOps,
int warmups,
int measures)
{ qieroom.com,
int
n
=
a.length;
int
outer
=
(
int
)Math.max(
1
, targetOps / n);
long
actualOps
=
(
long
)n * outer;
// warmup
long
ck
=
0
;
for
(
int
i
=
0
; i < warmups; i++) {
ck ^= runOnce(op, a, b, e, mod, outer);
}
long
[] times =
new
long
[measures];
for
(
int
i
=
0
; i < measures; i++) {
long
t0
=
System.nanoTime();
long
c
=
runOnce(op, a, b, e, mod, outer);
long
t1
=
System.nanoTime();
ck ^= c;
times[i] = (t1 - t0);
}
Arrays.sort(times); wap.7632.com.cn,
long
median
=
times[times.length /
2
];
double
nsPerOp
=
(
double
)median / (
double
)actualOps;
return
new
Result
(lang, bits, op, actualOps, nsPerOp, ck);
}
static
void
printHuman
(List<Result> results)
{
System.out.println(
"Java BigInteger benchmark"
);
System.out.println(
"java.version="
+ System.getProperty(
"java.version"
));
System.out.println(
"java.vm.name="
+ System.getProperty(
"java.vm.name"
));
System.out.println();
System.out.printf(Locale.ROOT,
"%-6s %-9s %-12s %-12s\n"
,
"Bits"
,
"Op"
,
"ns/op(med)"
,
"ops/run"
);
for
(Result r : results) {
System.out.printf(Locale.ROOT,
"%-6d %-9s %-12.3f %-12d\n"
, r.bits, r.op.name(), r.nsPerOp, r.ops);
}
System.out.println();
System.out.println(
"checksum="
+ results.stream().mapToLong(x -> x.checksum).reduce(
0L
, (x,y)->x^y));
}
public
static
void
main
(String[] args)
{
boolean
json
=
false
;
for
(String a : args)
if
(a.equals(
"--json"
)) json =
true
;
int
warmups
=
5
;
int
measures
=
11
; wap.jtwL.com.cn,
int
[] bitSizes =
new
int
[]{
256
,
1024
,
4096
};
List<Result> results =
new
ArrayList
<>();
for
(
int
bits : bitSizes) {
BigInteger
mod
=
genModulus(bits,
0xA1B2C3D4E5F60708L
^ bits);
// add/mul datasets
int
nAddMul
=
1024
;
BigInteger[] a = genBigInts(bits, nAddMul,
0x1111222233334444L
^ bits);
BigInteger[] b = genBigInts(bits, nAddMul,
0x9999AAAABBBBCCCCL
^ bits);
// modpow datasets (smaller)
int
nPow
=
256
;
BigInteger[] ap = genBigInts(bits, nPow,
0x13579BDF2468ACE0L
^ bits);
BigInteger[] ep =wap.xyxdLsm.com, genBigInts(Math.min(bits,
512
), nPow,
0x0FEDCBA987654321L
^ bits);
long
addOps;
long
mulOps;
long
powOps;
if
(bits ==
256
) {
addOps =
2_000_000L
;
mulOps =
500_000L
;
powOps =
8_000L
;
}
else
if
(bits ==
1024
) {
addOps =
1_000_000L
;
mulOps =
120_000L
;
powOps =
1_500L
;
}
else
{
addOps =
200_000L
;
mulOps =
20_000L
;
powOps =
250L
;
}
results.add(bench(
"java"
, bits, wap.LeLeypay.cn,Op.ADD_MOD, a, b,
null
, mod, addOps, warmups, measures));
results.add(bench(
"java"
, bits, Op.MUL_MOD, a, b,
null
, mod, mulOps, warmups, measures));
results.add(bench(
"java"
, bits, Op.MODPOW, ap,
null
, ep, mod, powOps, warmups, measures));
}
if
(json) { m.jtwL.com.cn,
for
(Result r : results) System.out.println(r.toJson());
}
else
{
printHuman(results);
using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Numerics; sealed class SplitMix64 { private ulong _x; public SplitMix64( ulong seed) => _x = seed; public ulong NextUInt64() { ulong z = (_x += 0x9E3779B97F4A7C15 UL); z = (z ^ (z >> 30 )) * 0xBF58476D1CE4E5B9 UL; z = (z ^ (z >> 27 )) * 0x94D049BB133111EB UL; return z ^ (z >> 31 ); } public void NextBytes( byte[] dst) { int i = 0 ; while (i < dst.Length) { ulong v = NextUInt64(); for ( int k = 0 ; k < 8 && i < dst.Length; k++) { dst[i++] = ( byte )(v >> ( 56 - 8 * k)); // big-endian stream } } } } enum Op { ADD_MOD, MUL_MOD, MODPOW } record Result ( string Lang , int Bits , Op Op , long Ops , double NsPerOp , long Checksum ) { public string ToJson() => string .Create(CultureInfo.InvariantCulture, wap.qieroom.com, $"{{\"lang\":\" {Lang}\",\"bits\": {Bits},\"op\":\" {Op}\",\"ops\": {Ops},\"nsPerOp\": {NsPerOp:F3},\"checksum\": {Checksum}}}" ); } static class BigIntBench { m.psnsd.com, static BigInteger[] GenBigInts( int bitSize, int count, ulong seed) { var rng = new SplitMix64(seed); int byteLen = (bitSize + 7 ) / 8 ; var arr = new BigInteger[count]; var buf = new byte [byteLen]; int topBit = (bitSize - 1 ) % 8 ; byte topMask = ( byte )( 1 << topBit); for ( int i = 0 ; i < count; i++) { rng.NextBytes(buf); buf[ 0 ] |= topMask; www.szfort.com.cn, // unsigned + big-endian prevents negative arr[i] = new BigInteger(buf, isUnsigned: true , isBigEndian: true ); } return arr; } static BigInteger GenModulus( int bitSize, ulong seed) { var rng = new SplitMix64(seed); wap.jtwL.com.cn, int byteLen = (bitSize + 7 ) / 8 ; var buf = new byte [byteLen]; rng.NextBytes(buf); int topBit = (bitSize - 1 ) % 8 ; buf[ 0 ] |= ( byte )( 1 << topBit); buf[^ 1 ] |= 1 ; // odd return new BigInteger(buf, isUnsigned: true , isBigEndian: true ); } static long RunOnce( Op op, BigInteger[] a, BigInteger[] b, BigInteger[] e, BigInteger mod, int outer) { BigInteger acc = BigInteger.Zero; int n = a.Length; switch (op) { case Op.ADD_MOD: for ( int o = 0 ; o < outer; o++) for ( int i = 0 ; i < n; i++) { m.cowinbuy.com, var r = (a[i] + b[i]) % mod; acc ^= r; } break ; case Op.MUL_MOD: for ( int o = 0 ; o < outer; o++) for ( int i = 0 ; i < n; i++) { var r = (a[i] * b[i]) % mod; acc ^= r; } break ; case Op.MODPOW: for ( int o = 0 ; o < outer; o++) for ( int i = 0 ; i < n; i++) { var r = BigInteger.ModPow(a[i], e[i], mod); acc ^= r; } break ; } return ( long )(acc & long .MaxValue); // stable checksum } static Result Bench( string lang, int bits, Op op, BigInteger[] a, BigInteger[] b, BigInteger[] e, BigInteger mod, long targetOps, int warmups, int measures) { int n = a.Length; int outer = ( int )Math.Max( 1 , targetOps / n); long actualOps = ( long )n * outer; long ck = 0 ; for ( int i = 0 ; i < warmups; i++) ck ^= RunOnce(op, a, b, e, mod, outer);m.zjtgjx.net, long [] timesNs = new long [measures]; for ( int i = 0 ; i < measures; i++) { var sw = Stopwatch.StartNew(); long c = RunOnce(op, a, b, e, mod, outer); sw.Stop(); ck ^= c; // Stopwatch ticks to ns timesNs[i] = ( long )(sw.ElapsedTicks * ( 1 _000_000_000 .0 / Stopwatch.Frequency)); } Array.Sort(timesNs); m.7632.com.cn, wap.jsastone.com.cn long median = timesNs[timesNs.Length / 2 ]; double nsPerOp = ( double )median / actualOps; return new Result(lang, bits, op, actualOps, nsPerOp, ck); } static void PrintHuman( List<Result> results) { Console.WriteLine( "C# BigInteger benchmark" ); Console.WriteLine( $"dotnet.version= {Environment.Version}" ); Console.WriteLine( $"os= {System.Runtime.InteropServices.RuntimeInformation.OSDescription}" ); Console.WriteLine( $"arch= {System.Runtime.InteropServices.RuntimeInformation.OSArchitecture}" ); Console.WriteLine();m.wsbbt.com, Console.WriteLine( $" { "Bits", -6} { "Op", -9} { "ns/op(med)", -12} { "ops/run", -12}" ); foreach ( var r in results) Console.WriteLine( string .Create(CultureInfo.InvariantCulture, $" {r.Bits, -6} {r.Op, -9} {r.NsPerOp, -12:F3} {r.Ops, -12}" )); Console.WriteLine(); long checksum = 0 ; wap.xyxdLsm.com, foreach ( var r in results) checksum ^= r.Checksum; Console.WriteLine( $"checksum= {checksum}" ); } public static int Main( string[] args) { bool json = args.Any(a => a == "--json" ); int warmups = 5 ; int measures = 11 ; int [] bitSizes = [ 256 , 1024 , 4096 ]; var results = new List<Result>(); wap.yousLab.com, foreach ( int bits in bitSizes) { var mod = GenModulus(bits, 0xA1B2C3D4E5F60708 UL ^ ( uint )bits); int nAddMul = 1024 ; var a = GenBigInts(bits, nAddMul, 0x1111222233334444 UL ^ ( uint )bits); var b = GenBigInts(bits, nAddMul, 0x9999AAAABBBBCCCC UL ^ ( uint )bits); int nPow = 256 ; wap.zjtgjx.net, , var ap = GenBigInts(bits, nPow, 0x13579BDF2468ACE0 UL ^ ( uint )bits); var ep = GenBigInts(Math.Min(bits, 512 ), nPow, 0x0FEDCBA987654321 UL ^ ( uint )bits); long addOps = bits switch { 256 => 2 _000_000L, 1024 => 1 _000_000L, _ => 200 _000L }; long mulOps = bits switch { 256 => 500 _000L, 1024 => 120 _000L, _ => 20 _000L }; long powOps = bits switch { 256 => 8 _000L, 1024 => 1 _500L, _ => 250L }; results.Add(Bench( "csharp" , bits, Op.ADD_MOD, a, b, null !, mod, addOps, warmups, measures)); results.Add(Bench( "csharp" , www.zjtgjx.net bits, Op.MUL_MOD, a, b, null !, mod, mulOps, warmups, measures)); results.Add(Bench( "csharp" , bits, Op.MODPOW, ap, null !, ep, mod, powOps, warmups, measures)); } if (json) { foreach ( var r in results) Console.WriteLine(r.ToJson()); } else {
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3109273/ ,如需转载,请注明出处,否则将追究法律责任。