看到网友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