问题
同步influxdb有些数据没有,不知道啥原因,后来百度发现时间需要唯一,毫秒还会重复,只能采用纳秒处理了
java实现
TimeStampUtils.java
package com.wujialiang;
/**
* 获取纳秒值的工具类
*/
public class TimeStampUtils {
/**
* 递增数初始值
*/
private static long randomNum = 1L;
/**
* 递增数最大值,可根据并发情况适当调整
* 比如1秒钟生成1万条数据,这个值尽量接近或者大于1万
*/
private static final long RANDOM_NUM_MAX = 999L;
public static long getTimeStamp() {
long curRandomNum;
synchronized (TimeStampUtils.class) {
if (randomNum > RANDOM_NUM_MAX) {
randomNum = 1;
}
curRandomNum = randomNum++;
}
return System.currentTimeMillis() * 1000000L + System.nanoTime() % 1000000L + curRandomNum;
}
}
测试
public static void main( String[] args )
{
for (int i = 0; i < 100; i++) {
System.out.println(TimeStampUtils.getTimeStamp());
}
}
C#实现
NanoHelper.cs
using System.Diagnostics;
namespace InfluxdbStu01;
public class NanoHelper
{
private static readonly object lockObj = new object();
/// <summary>
/// 递增数初始值
/// </summary>
private static long randomNum = 1L;
/// <summary>
/// 递增数最大值,可根据并发情况适当调整
/// 比如1秒钟生成1万条数据,这个值尽量接近或者大于1万
/// </summary>
private const long RANDOM_NUM_MAX = 999L;
/// <summary>
/// 返回纳秒
/// </summary>
/// <returns>返回的结果是纳秒</returns>
public static long getTimeStamp()
{
long curRandomNum;
lock (lockObj)
{
if (randomNum > RANDOM_NUM_MAX)
{
randomNum = 1;
}
curRandomNum = randomNum++;
}
long nanoPart = Stopwatch.GetTimestamp(); // 计时器刻度(不是纳秒)
long nowTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
/*
皮秒 纳秒 微秒 毫秒 秒 ps、ns、us、ms、s 时间单位之间的换算
1,000,000,000,000皮秒=1秒 (12个0)ps -> s
1,000,000,000纳秒=1秒 (9个0) ns -> s
1,000,000微秒=1秒 (6个0)us -> s
1,000毫秒=1秒 (3个0) ms -> s
*/
return nowTimestamp* 1000000L
+ nanoPart % 1000000L + curRandomNum;
}
}
测试
NanoHelper.getTimeStamp()
优化
上面代码效率比较低,优化一下,这个不加锁,效率比较高但是会有重复,要求不高可以使用
using System.Diagnostics;
namespace InfluxdbStu01;
public class TimeStampHelper
{
private static readonly Stopwatch StopwatchInstance = new Stopwatch();
// 静态构造函数,确保Stopwatch在类首次被访问时开始
static TimeStampHelper()
{
StopwatchInstance.Start();
}
/// <summary>
/// 返回一个组合了Unix时间毫秒和Stopwatch刻度的“时间戳”
/// 注意:这不是真正的纳秒精度,但提供了比毫秒更高的精度
/// 会重复
/// </summary>
/// <returns>返回一个long类型的时间戳</returns>
public static long GetTimeStamp()
{
long nowTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
long stopwatchTicks = StopwatchInstance.ElapsedTicks; // 获取Stopwatch的刻度
// 这里假设Stopwatch的刻度频率足够高,以提供亚毫秒级别的精度
// 但注意,这仍然不是纳秒级别的精度
// 如果需要纳秒级别的精度,您可能需要考虑使用硬件计时器或其他高精度时间源
// 根据Stopwatch的Frequency将刻度转换为更小的单位(例如微秒或纳秒的近似值)
// 但由于Frequency的单位是TicksPerSecond,我们需要先将其转换为纳秒/刻度,然后再乘以刻度数
double nanosecondsPerTick = 1_000_000_000.0 / Stopwatch.Frequency; // 纳秒/刻度
long subMillisecondNanoseconds = (long)(stopwatchTicks * nanosecondsPerTick);
// 注意:由于double到long的转换,这里可能会有精度损失
// 如果需要更高的精度,可以保留为double或更大的整数类型,但这样会增加存储和处理的复杂性
// 将毫秒时间戳和亚毫秒纳秒部分组合起来
// 这里假设subMillisecondNanoseconds不会大于999,999,999(即小于1毫秒),这通常是合理的
return nowTimestamp * 1_000_000_000L + subMillisecondNanoseconds;
}
}
100万数据54毫秒,但是重复数据有一半,优化重复的问题
namespace InfluxdbStu01;
public class TimeStampHelper2
{
private static readonly object counterLock = new object(); // 用于同步的锁对象
private static long counter; // 简单的递增计数器
/// <summary>
/// 返回一个组合了Unix时间毫秒和递增计数器的“时间戳”
/// 注意:这不是真正的纳秒精度,但在毫秒级别上增加了计数器以防止短时间内重复
/// </summary>
/// <returns>返回一个long类型的时间戳</returns>
public static long GetTimeStamp2()
{
long nowTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// 使用锁来确保计数器的线程安全递增
lock (counterLock)
{
if (counter >= int.MaxValue) // 防止计数器溢出(可选)
{
counter = 0; // 重置计数器(可选)
}
counter++;
}
// 将毫秒时间戳和计数器组合起来(这里简单地将计数器作为额外的精度添加)
// 注意:这种方法仍然可能在极短的时间内产生重复,但比仅使用时间戳的可能性小
return (nowTimestamp * 1000) + (int)counter; // 假设counter不会超过int范围
}
}
100万数据,53毫秒,没有重复,如果数据量够大的情况可能会出现,但是目前满足业务需求
参考
https://blog.csdn.net/hahawangzi520/article/details/134846374