Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript JS:使用字典比在数组中循环快吗?_Javascript_Performance_Loops_Dictionary - Fatal编程技术网

Javascript JS:使用字典比在数组中循环快吗?

Javascript JS:使用字典比在数组中循环快吗?,javascript,performance,loops,dictionary,Javascript,Performance,Loops,Dictionary,我正在Nodejs中构建一些程序,它需要在内存中跟踪大量用户。此外,我还将使用一个函数按id过滤用户。代码如下所示: const users = [ { id: 1, name: 'John', friends: [3, 6, 8] }, { id: 2, name: 'Mark', friends: [567, 23] } ] function getUserByI

我正在Nodejs中构建一些程序,它需要在内存中跟踪大量用户。此外,我还将使用一个函数按id过滤用户。代码如下所示:

const users = [
    {
        id: 1,
        name: 'John',
        friends: [3, 6, 8]
    },
    {
        id: 2,
        name: 'Mark',
        friends: [567, 23]
    }
]

function getUserById(userId) {
    const user = users.filter(user => user.id === userId);
    return user[0];
}
问题是,这个版本是否通常更快(每个键都是用户id):


我的直觉告诉我这本字典更快。事实是什么?

不保证对象中的键查找时间。它也可能是O(n),但如果您多次动态查找密钥,大多数引擎都会朝着O(1)方向进行优化。过滤数组是O(n),
.find()
但是平均速度要快两倍:

  return users.find(user => user.id === userId);
现在唯一保证O(1)查找的数据结构是
Map
s:

 const userMap = new Map(users.map(u => [u.id, u]));
 console.log(userMap.get("test"));

但是,如果您计划以非常大的规模(100k是大的)执行此任务,我宁愿将此任务移动到数据库中,因为它针对这些任务进行了大量优化。MongoDB很容易采用,Redis会很快,还有很多其他的。我写了一个小脚本,可以复制粘贴到控制台,显示这个问题的实际数据,并在实践中改变Jonas Wilms的答案

function random_int_from_range(x, y) {
return (x + Math.floor(Math.random() * (y - x + 1)));
}

function generate_name(length_min, length_max) {
  var letters = 'abcdefghijklmnopqrstuvwxyz';
  var name_array = [];

  for (var i = 0; i <= random_int_from_range(length_min, length_max); i ++) {
      name_array.push(letters.charAt(Math.floor(Math.random() * letters.length +1)));
  }

  return name_array.join('')
}

function generate_friends_array(length_min, length_max, num_users) {
  friends_array = [];
  for (var i = 0; i < random_int_from_range(length_min, length_max); i++) {
    friends_array.push(random_int_from_range(0, num_users - 1))
  }

  return friends_array
}

function generate_users_dict(num_users) {
  var users = {};
  for (var i = 0; i < num_users; i++) {
    users[i] = {
        'id': i,
        'name': generate_name(4,6),
        'friends': generate_friends_array(0, 20, num_users)
    }
  }

  return users
}

function generate_users_list_from_dict(users_dict) {
  var users_list = [];

  for (var key in  users_dict) {
    users_list.push(users_dict[key]);
  }

  return users_list;
}

function get_diff_in_seconds_from_two_milisecond_values(early_value, late_value) {
  return (late_value - early_value) / 1000
}

function get_user_by_id_from_dict(users_dict, user_id) {
  return users_dict[user_id]
}

function get_user_by_id_from_list(users_list, user_id) {
  const users = users_list.filter(user => user.id === user_id);
  return users[0]
}

function get_time_for_retrieval_of_item_from_object(object, object_length) {
  var function_names = ['get_user_by_id_from_dict', 'get_user_by_id_from_list'];
  var random_id = random_int_from_range(0, object_length - 1);
  var function_name = '';

  if (Array.isArray(object)) {
    function_name = function_names[1];
  }
  else {
    function_name = function_names[0];
  }

  var time_before_retrieval = new Date().getTime();
  window[function_name](object, random_id);
  var time_after_retrieval = new Date().getTime();

  return get_diff_in_seconds_from_two_milisecond_values(time_before_retrieval, 
  time_after_retrieval);
}

function test_retrieval_times(number_of_users, tests_num, object_type) {
  var users_dict = generate_users_dict(number_of_users);
  var users_list = generate_users_list_from_dict(users_dict);
  var times_array = [];
  var object = '';

  if (object_type == 'dict') {
    object = users_dict;
  }
  else {
    object = users_list;
  }

  for (var i = 0; i < tests_num; i++) {
    times_array.push(get_time_for_retrieval_of_item_from_object(object, 
    number_of_users));
  }

  return times_array;
}

function get_average_retrieval_time(object_type, number_of_users, 
                                    numbers_of_retrievals) {
  var retrieval_times = test_retrieval_times(number_of_users, numbers_of_retrievals, 
                                             object_type);
  var sum = 0;

  for (var i = 0; i < retrieval_times.length; i++) {
    sum += retrieval_times[i];
  }

  console.log('average retrieval time for ' +  object_type + ': ' + sum / 
              numbers_of_retrievals);
}

var number_of_users = parseInt(prompt("Please enter object size", "1000000"));
var number_of_retrievals = parseInt(prompt("Please enter number of retrievals", 
                                    "100"));

get_average_retrieval_time('dict', number_of_users, number_of_retrievals);
get_average_retrieval_time('list', number_of_users, number_of_retrievals);
函数范围(x,y)中的随机整数{
返回(x+Math.floor(Math.random()*(y-x+1));
}
函数生成\名称(长度\最小值,长度\最大值){
var字母='ABCDEFGHIjklmnopqrstuvxyz';
变量名称_数组=[];
for(var i=0;i user.id==user\u id);
返回用户[0]
}
函数get_time_,用于从_对象(对象,对象长度)检索_项_{
var函数_name=['get_user_by_id_from_dict','get_user_by_id_from_list'];
var random\u id=来自\u范围的随机\u int\u(0,对象\u长度-1);
var函数_name='';
if(Array.isArray(对象)){
函数名称=函数名称[1];
}
否则{
函数名称=函数名称[0];
}
检索前的变量时间=新日期().getTime();
窗口[功能名称](对象,随机id);
检索后的变量时间=新日期().getTime();
从两个毫秒值(检索前的时间)返回get_diff_in_seconds_,
检索后的时间);
}
功能测试检索次数(用户数、测试数、对象类型){
var users\u dict=生成用户数(用户数);
var users\u list=从用户目录(users\u dict)生成用户列表;
var times_数组=[];
var对象=“”;
如果(对象类型=='dict'){
对象=用户\u dict;
}
否则{
对象=用户列表;
}
对于(var i=0;i

测试结果将打印到控制台。

假设100K用户当您使用数据库时,您的100K用户会很感激。如果您真的需要将它们存储在内存中,您可能需要查看一下Redist。此状态将用于跟踪通过SocketIO连接的用户,这就是使用内存的原因。关于数据库:这将不仅仅是站点用户的列表,而是通过SocketIO连接的用户的列表。这就是为什么我需要有一个记忆track@sheff2k1然后我会将一个附加属性直接存储到socket对象中。是的,我计划在每个套接字上放置一个“userData”属性,但我仍然需要跟踪所有连接的套接字,为了有时执行一些特定于套接字的任务。@sheff2k1将用户移动到数据库还允许您并行运行多个Nodejs WebSocket,这将超过内存中的单个线程Nodejs服务器。是的,这是一个很好的观点。注意,我已经在一个SQL数据库中有了用户。此状态对象只是在套接字和登录用户之间创建某种关联的一种方法(登录系统与SocketIO完全分离)。
function random_int_from_range(x, y) {
return (x + Math.floor(Math.random() * (y - x + 1)));
}

function generate_name(length_min, length_max) {
  var letters = 'abcdefghijklmnopqrstuvwxyz';
  var name_array = [];

  for (var i = 0; i <= random_int_from_range(length_min, length_max); i ++) {
      name_array.push(letters.charAt(Math.floor(Math.random() * letters.length +1)));
  }

  return name_array.join('')
}

function generate_friends_array(length_min, length_max, num_users) {
  friends_array = [];
  for (var i = 0; i < random_int_from_range(length_min, length_max); i++) {
    friends_array.push(random_int_from_range(0, num_users - 1))
  }

  return friends_array
}

function generate_users_dict(num_users) {
  var users = {};
  for (var i = 0; i < num_users; i++) {
    users[i] = {
        'id': i,
        'name': generate_name(4,6),
        'friends': generate_friends_array(0, 20, num_users)
    }
  }

  return users
}

function generate_users_list_from_dict(users_dict) {
  var users_list = [];

  for (var key in  users_dict) {
    users_list.push(users_dict[key]);
  }

  return users_list;
}

function get_diff_in_seconds_from_two_milisecond_values(early_value, late_value) {
  return (late_value - early_value) / 1000
}

function get_user_by_id_from_dict(users_dict, user_id) {
  return users_dict[user_id]
}

function get_user_by_id_from_list(users_list, user_id) {
  const users = users_list.filter(user => user.id === user_id);
  return users[0]
}

function get_time_for_retrieval_of_item_from_object(object, object_length) {
  var function_names = ['get_user_by_id_from_dict', 'get_user_by_id_from_list'];
  var random_id = random_int_from_range(0, object_length - 1);
  var function_name = '';

  if (Array.isArray(object)) {
    function_name = function_names[1];
  }
  else {
    function_name = function_names[0];
  }

  var time_before_retrieval = new Date().getTime();
  window[function_name](object, random_id);
  var time_after_retrieval = new Date().getTime();

  return get_diff_in_seconds_from_two_milisecond_values(time_before_retrieval, 
  time_after_retrieval);
}

function test_retrieval_times(number_of_users, tests_num, object_type) {
  var users_dict = generate_users_dict(number_of_users);
  var users_list = generate_users_list_from_dict(users_dict);
  var times_array = [];
  var object = '';

  if (object_type == 'dict') {
    object = users_dict;
  }
  else {
    object = users_list;
  }

  for (var i = 0; i < tests_num; i++) {
    times_array.push(get_time_for_retrieval_of_item_from_object(object, 
    number_of_users));
  }

  return times_array;
}

function get_average_retrieval_time(object_type, number_of_users, 
                                    numbers_of_retrievals) {
  var retrieval_times = test_retrieval_times(number_of_users, numbers_of_retrievals, 
                                             object_type);
  var sum = 0;

  for (var i = 0; i < retrieval_times.length; i++) {
    sum += retrieval_times[i];
  }

  console.log('average retrieval time for ' +  object_type + ': ' + sum / 
              numbers_of_retrievals);
}

var number_of_users = parseInt(prompt("Please enter object size", "1000000"));
var number_of_retrievals = parseInt(prompt("Please enter number of retrievals", 
                                    "100"));

get_average_retrieval_time('dict', number_of_users, number_of_retrievals);
get_average_retrieval_time('list', number_of_users, number_of_retrievals);