我编写了一个小程序来生成唯一的ID并打印出所用时间的费用。以下是代码:
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);
}
}
}
结果似乎有些奇怪。
53
690531076282879
5
690531076281343
0
690531076283903
0
690531076282367
0
690531076280831
0
690531076283391
0
690531076281855
0
690531076284415
0
690531076282879
0
690531076281343
它用0毫秒得到正确的结果,而C++版本需要230毫秒才能得到一个结果。当我将内部循环的数目从1亿更改为类型为double的1e9时,每个结果需要超过1秒钟。这怎么可能?
我改变了C++版本的循环次数,但完全没有变化。所以我猜Java优化了循环,省略了前999999999个循环。Java如何优化它并且不花费任何代价却能获得正确的结果?如何优化相同代码的C++版本以跳过无用的循环?我使用-O3标志,但似乎没有起作用。
#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;
}
这是C++版本的代码,以及它的结果:
1419
690531076282879
1385
690531076281343
1388
690531076283903
1457
690531076282367
1407
690531076280831
1402
690531076283391
1441
690531076281855
1389
690531076284415
1395
690531076282879
1360
690531076281343
对于计时,这只是主函数中的代码。我知道算法是错误的,我只是好奇为什么Java可以做到这一点,以及如何让C++跳过循环。
关于计时,这只是主函数中的代码而已。我知道算法有问题,但我只是好奇为什么Java能够实现,如何让C++也能跳过循环。
java
中添加-XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
标志。 - Kayaman