英文:
Is it reasonable to use Int64 instead of DateTime / TimeSpan in the Domain-level structures?
问题
在我的解决方案的领域项目(.NET Framework)中,我有以下简单的结构:
public struct Candlestick
{
public DateTime OpenTime;
public DateTime CloseTime;
public double Open;
public double High;
public double Low;
public double Close;
public double Volume;
}
在我的业务逻辑中,我有许多方法用于在Candlestick结构的大型列表中执行基于时间的搜索。例如:
public static int IndexOfFirst(this IReadOnlyList<Candlestick> data, DateTime from)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
int count = data.Count;
if (count == 0) return -1;
int fromIdx = 0;
while (data[fromIdx].OpenTime < from)
{
if (++fromIdx == count)
{
return -1;
}
}
return fromIdx;
}
是否一般来说,使用long
(Int64
)类型作为Candlestick结构中的时间变量是一个好主意,以便逻辑层能够更快地操作这个结构?另外,我打算在应用程序层级保留相应的类(视图模型层中的CandlestickVM),其中时间变量的类型是DateTime
。
为了验证我使用Int64
的想法,我在dotnetfiddle.net上运行了一个简单的性能测试:
DateTime a = new DateTime(2023, 01, 01);
DateTime b = new DateTime(2023, 02, 01);
TimeSpan incr = new TimeSpan(1);
DateTime now = a;
Stopwatch sw = Stopwatch.StartNew();
while (now < b)
{
now += incr;
}
sw.Stop();
Console.WriteLine($"运行日期和时间测试耗时:{sw.Elapsed}");
long incr2 = incr.Ticks;
long now2 = a.Ticks;
long bticks = b.Ticks;
sw.Restart();
while (now2 < bticks)
{
now2 += incr2;
}
sw.Stop();
Console.WriteLine($"运行长整数测试耗时:{sw.Elapsed}");
结果如下:
运行日期和时间测试耗时:00:00:04.8027716
运行长整数测试耗时:00:00:00.9261338
如果您要求只翻译代码部分,以上即为代码部分的翻译。
英文:
I have the following simple structure in my solution's domain project (.NET Framework):
public struct Candlestick
{
public DateTime OpenTime;
public DateTime CloseTime;
public double Open;
public double High;
public double Low;
public double Close;
public double Volume;
}
In my business logic I have many methods that perform time-based search in big lists of Candlestick structures. For example:
public static int IndexOfFirst(this IReadOnlyList<Candlestick> data, DateTime from)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
int count = data.Count;
if (count == 0) return -1;
int fromIdx = 0;
while (data[fromIdx].OpenTime < from)
{
if (++fromIdx == count)
{
return -1;
}
}
return fromIdx;
}
Would it be generally a good idea to use the long (Int64
) type for time variables in the Candlestick struct, so that the logic layer can operate faster with this structure? Also, I mean to keep the corresponding class on the application level (CandlestickVM in the view-model layer) with the time variables of the type DateTime
.
To check my idea of using Int64
, I ran a simple performance test on dotnetfiddle.net:
DateTime a = new DateTime(2023, 01, 01);
DateTime b = new DateTime(2023, 02, 01);
TimeSpan incr = new TimeSpan(1);
DateTime now = a;
Stopwatch sw = Stopwatch.StartNew();
while (now < b)
{
now += incr;
}
sw.Stop();
Console.WriteLine($"It took {sw.Elapsed} to run the Date & Time test.");
long incr2 = incr.Ticks;
long now2 = a.Ticks;
long bticks = b.Ticks;
sw.Restart();
while (now2 < bticks)
{
now2 += incr2;
}
sw.Stop();
Console.WriteLine($"It took {sw.Elapsed} to run the long test.");
The results is as the following:
It took 00:00:04.8027716 to run the Date & Time test.
It took 00:00:00.9261338 to run the long test.
答案1
得分: 1
您的代码中,与 DateTime
相关的操作仅涉及比较,而您的基准测试执行了加法操作。我使用 BenchmarkDotNet 创建了一个仅涉及比较的简单基准测试,以下是代码和结果:
[SimpleJob(RuntimeMoniker.Net70)]
[RPlotExporter]
public class LongXDateTime
{
[Params(1_000_000)]
private int N;
private DateTime[] Da;
private DateTime[] Db;
private long[] La;
private long[] Lb;
[GlobalSetup]
public void Setup()
{
Da = new DateTime[N];
Db = a DateTime[N];
La = new long[N];
Lb = new long[N];
for (int i = 0; i < N; i++)
{
La[i] = Random.Shared.NextInt64(DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks);
Lb[i] = Random.Shared.NextInt64(DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks);
Da[i] = new DateTime(La[i]);
Db[i] = new DateTime(Lb[i]);
}
}
[Benchmark]
public bool[] LongMethod()
{
bool[] result = new bool[La.Length];
for(int i = 0; i < La.Length; i++)
{
result[i] = La[i] < Lb[i];
}
return result;
}
[Benchmark]
public bool[] DateTimeMethod()
{
bool[] result = new bool[Da.Length];
for (int i = 0; i < Da.Length; i++)
{
result[i] = Da[i] < Db[i];
}
return result;
}
}
结果如下:
| Method | N | Mean | Error | StdDev |
|--------------- |----------- |---------:|----------:|----------:|
| LongMethod | 1000000 | 1.460 ms | 0.0253 ms | 0.0370 ms |
| DateTimeMethod | 1000000 | 1.467 ms | 0.0292 ms | 0.0380 ms |
因此,切换到使用 long
可能不会在应用性能方面具有重要意义,而且它:
- 可能不会对应用性能产生影响
- 可能不够可读
- 不够安全,因为您会失去类型安全性
此外,建议阅读 Eric Lippert 关于性能的博客。
英文:
Your code only operations with DateTime
are comparisons, while your benchmark does adition. I made a simple benchmark using BenchmarkDtonet with comparisons only and here are the code and results:
[SimpleJob(RuntimeMoniker.Net70)]
[RPlotExporter]
public class LongXDateTime
{
[Params(1_000_000)]
private int N;
private DateTime[] Da;
private DateTime[] Db;
private long[] La;
private long[] Lb;
[GlobalSetup]
public void Setup()
{
Da = new DateTime[N];
Db = new DateTime[N];
La = new long[N];
Lb = new long[N];
for (int i = 0; i < N; i++)
{
La[i] = Random.Shared.NextInt64(DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks);
Lb[i] = Random.Shared.NextInt64(DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks);
Da[i] = new DateTime(La[i]);
Db[i] = new DateTime(Lb[i]);
}
}
[Benchmark]
public bool[] LongMethod()
{
bool[] result = new bool[La.Length];
for(int i = 0; i < La.Length; i++)
{
result[i] = La[i] < Lb[i];
}
return result;
}
[Benchmark]
public bool[] DateTimeMethod()
{
bool[] result = new bool[Da.Length];
for (int i = 0; i < Da.Length; i++)
{
result[i] = Da[i] < Db[i];
}
return result;
}
}
Result:
| Method | N | Mean | Error | StdDev |
|--------------- |----------- |---------:|----------:|----------:|
| LongMethod | 1000000 | 1.460 ms | 0.0253 ms | 0.0370 ms |
| DateTimeMethod | 1000000 | 1.467 ms | 0.0292 ms | 0.0380 ms |
So switching to long:
- might not be relevant in terms of application performance
- Is less readable
- Is less safe, since you lose type safety
Also, recommend reading Eric Lippert Blog about performance
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论