I have written a little program to generate the unique ID. And print out the cost of time. Here is the code:
public class JavaSF_OLD {
static int randomNumberShiftBits = 12;
static int randomNumberMask = (1 << randomNumberShiftBits) - 1;
static int machineNumberShiftBits = 5;
static int machineNumberMask = (1 << machineNumberShiftBits) - 1;
static int dataCenterNumberShiftBits = 5;
static int dataCenterNumberMask = (1 << dataCenterNumberShiftBits) - 1;
static int dateTimeShiftBits = 41;
static long dateTimeMask = (1L << dateTimeShiftBits)-1;
static int snowFlakeId = 0;
static long lastTimeStamp = 0;
static int DataCenterID = 1;
static int MachineID = 1;
public static long get() {
// var current = System.currentTimeMillis();
var current = 164635438;
if (current != lastTimeStamp) {
snowFlakeId = 0;
lastTimeStamp=current;
}else{
snowFlakeId++;
}
long id = 0;
id |= current&dateTimeMask;
id <<= dataCenterNumberShiftBits;
id |= DataCenterID&dataCenterNumberMask;
id <<= machineNumberShiftBits;
id |= MachineID&machineNumberMask;
id <<= randomNumberShiftBits;
id |= snowFlakeId & randomNumberMask;
return id;
}
public static void main(String[] args) {
long result = 0;
for (int out = 0; out < 10; out++) {
var start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
result = get();
}
var end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(result);
}
}
}
The result seems to be a little wierd.
53
690531076282879
5
690531076281343
0
690531076283903
0
690531076282367
0
690531076280831
0
690531076283391
0
690531076281855
0
690531076284415
0
690531076282879
0
690531076281343
It use 0 millionsecond to get the right result, while the C++ version needs 230 millionseconds to get one result. When I change the number of the inner loop from 1000000000 to 1e9, which is of type double, it takes more than one second to get per result. How could this be?
I change the number of loop of C++ version and there is no change at all. So I guess Java optimizes the loop and omit the first 999999999 loops. And how could Java optimize it actually and run it at no cost but get the correct result? And how to optimize C++ version of the same code to skip the useless loop? I use -O3 flag but it seems not working.
#include <iostream>
#include <chrono>
static const unsigned int randomNumberShiftBits = 12;
static const unsigned int randomNumberMask = (1u << randomNumberShiftBits) - 1;
static const unsigned int machineNumberShiftBits = 5;
static const unsigned int machineNumberMask = (1u << machineNumberShiftBits) - 1;
static const unsigned int dataCenterNumberShiftBits = 5;
static const unsigned int dataCenterNumberMask = (1u << dataCenterNumberShiftBits)-1;
static const unsigned int dateTimeShiftBits = 41;
static const unsigned long long dateTimeMask = (1ull << dateTimeShiftBits) - 1;
static uint32_t snowFlakeId = 0;
static unsigned long long lastTimeStamp = 0;
static unsigned int DataCenterID=1;
static unsigned int MachineID=1;
std::int64_t get() {
// auto current = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
auto current = 164635438;
if (current != lastTimeStamp) {
snowFlakeId = 0;
lastTimeStamp = current;
}else{
snowFlakeId++;
}
unsigned long long id = 0;
// Datetime part
id |= static_cast<unsigned long long>(static_cast<unsigned long long>(current) & dateTimeMask);
// DataCenter Part
id <<= dataCenterNumberShiftBits;
id |= static_cast<uint>(static_cast<uint>(DataCenterID)&dataCenterNumberMask);
// Machine Part
id <<= machineNumberShiftBits;
id |= static_cast<uint>(static_cast<uint>(MachineID)&machineNumberMask);
// Random Number Part
id <<= randomNumberShiftBits;
id |= static_cast<uint>(snowFlakeId&randomNumberMask);
return id;
}
int main() {
for (int out = 0; out < 10; out++) {
uint64_t result = 0;
auto start = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
for (int i = 0; i < 1000000000; i++) {
result = get();
}
auto end = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << (end - start) << std::endl;
std::cout<<result<<std::endl;
}
return 0;
}
This is the C++ version and the result of it:
1419
690531076282879
1385
690531076281343
1388
690531076283903
1457
690531076282367
1407
690531076280831
1402
690531076283391
1441
690531076281855
1389
690531076284415
1395
690531076282879
1360
690531076281343
As for measuring the time, it's just the code in the main function. I know the algorithm is wrong and I am just curious why Java could do that and how to make C++ skip the loop as well.