看到网友toozyxia(https://my.oschina.net/xiayongsheng/blog/4775399)的对比,突发奇想,增加Node.js的对比
golang:
package mainimport ( "fmt" "os" "reflect" "runtime/pprof" "runtime/trace" "strconv" "time" "unsafe")type CalcCollection struct { }func (c *CalcCollection) V0() { arr := map[string]int64{} for i := int64(0); i < 1000000; i++ { value := time.Now().Unix() key := strconv.FormatInt(i, 10) + "_" + strconv.FormatInt(value, 10) arr[key] = value } }func (c *CalcCollection) V1() { nums := int64(1000000) arr := make(map[string]int64, nums) // key,放循环外,可以重复使用 key := make([]byte, 0) for i := int64(0); i < nums; i++ { key = key[:0] value := time.Now().Unix() // 改用appendInt,去掉strconv内部[]byte转string的开销 key = strconv.AppendInt(key, i, 10) key = append(key, '_') key = strconv.AppendInt(key, value, 10) keyStr := string(key) arr[keyStr] = value } }func (c *CalcCollection) V2() { nums := int64(1000000) arr := make(map[string]int64, nums) // 计算key长度,申请存下所有key的[]byte keyLen := int64(len(strconv.FormatInt(nums, 10)) + 1 + 10) totalLen := keyLen * nums key := make([]byte, totalLen) for i := int64(0); i < nums; i++ { value := time.Now().Unix() // 计算当前循环key的位置 pos := i * keyLen b := key[pos:pos] b = strconv.AppendInt(b, i, 10) b = append(b, '_') b = strconv.AppendInt(b, value, 10) // 直接将[]byte转为string arr[*(*string)(unsafe.Pointer(&b))] = value } }// 以下代码请忽略, 作用如下:// 根据参数决定调用CalcCollection.V{ver}// 根据参数决定是否记录trace、profilefunc main() { ver := os.Args[len(os.Args)-2] isRecord := os.Args[len(os.Args)-1] == "t" calcReflect := reflect.ValueOf(&CalcCollection{}) methodName := "V" + ver m := calcReflect.MethodByName(methodName) if isRecord { traceFile, err := os.Create(methodName + "_trace.out") if err != nil { panic(err.Error()) } err = trace.Start(traceFile) if err != nil { panic("start trace fail :" + err.Error()) } defer trace.Stop() cpuFile, err := os.Create(methodName + "_cpu.out") if err != nil { panic(err.Error()) } defer cpuFile.Close() err = pprof.StartCPUProfile(cpuFile) if err != nil { panic("StartCPUProfile fail :" + err.Error()) } defer pprof.StopCPUProfile() memFile, err := os.Create(methodName + "_mem.out") if err != nil { panic(err.Error()) } defer pprof.WriteHeapProfile(memFile) } t := time.Now() m.Call(make([]reflect.Value, 0)) fmt.Println(methodName, time.Now().Sub(t)) }
php:
<?php $startTime = microtime(true); $arr = array(); for($i=0;$i<1000000;$i++){ $currentTime = time(); $key = $i . "_" .$currentTime; $arr[$key] = $currentTime; } $endTime = microtime(true); echo ($endTime - $startTime) * 1000 . "ms\r\n";
Node.js
let startTime = new Date().getTime();let arr = {};for (let i = 0; i < 1000000; i++) { let currentTime = new Date().getTime(); let key = i + '_' + currentTime; arr[key] = currentTime; }let endTime = new Date().getTime();console.log((endTime - startTime) + "ms");
Python
#!/usr/bin/pythonimport timeimport datetimedef currentTime(): return int(round(time.time() * 1000))startTime = currentTime()arr = {}for i in range(0, 1000000): cTime = currentTime() key = str(i) + '_' + str(cTime) arr[key] = cTime;endTime = currentTime()used = str(endTime - startTime)print (used, "ms \r\n")
虚拟机(Centos 8.2)下的测试结果:
[root@bogon tmp]# ./test -args 0 fV0 614.601327ms [root@bogon tmp]# ./test -args 1 fV1 330.952331ms [root@bogon tmp]# ./test -args 2 fV2 256.896306ms [root@bogon tmp]# php test.php300.05478858948ms [root@bogon tmp]# node --versionv14.15.0[root@bogon tmp]# node test.js1861ms [root@bogon tmp]# python3 test.py 1563 ms
这个对比测试不能代表语言的优劣,有想法的朋友在下面留言
采用JetLua的建议,使用Date.new()直接读取时间,省一次时间对象构造。
let startTime = new Date().getTime();let arr = {};for (let i = 0; i < 1000000; i++) { let currentTime = Date.now(); // new Date().getTime(); let key = i + '_' + currentTime; arr[key] = currentTime; }let endTime = new Date().getTime();console.log((endTime - startTime) + "ms");
运行:
[root@bogon tmp]# node test.js 1605ms