gpt4 book ai didi

javascript - Javascript 和 Socket.io 中的同步

转载 作者:行者123 更新时间:2023-12-02 15:54:23 25 4
gpt4 key购买 nike

我有一个运行以下代码的 Node.js 服务器,它使用 socket.io 库:

var Common = require('./common');
var _ = require('lodash');
var store = (function() {
var userMapByUserId = {};
var tokenSet = {};
var generateToken = function(userId) {
if (_.has(userMapByUserId, userId)) {
var token = '';
do {
token = Common.randomGenerator();
} while (_.has(tokenSet, token));
if (userMapByUserId[userId].tokens === undefined) {
userMapByUserId[userId].tokens = {};
}
userMapByUserId[userId].tokens[token] = true;
}
};
var deleteToken = function(userId, tokenValue) {
if (_.has(userMapByUserId, userId)) {
if (userMapByUserId[userId].tokens !== undefined) {
userMapByUserId[userId].tokens = _.omit(userMapByUserId[userId].tokens, tokenValue);
}
if (_.has(tokenSet, tokenValue)) {
tokenSet = _.omit(tokenSet, tokenValue);
}
}
};
return {
generateToken: generateToken,
deleteToken: deleteToken
};
}());

module.exports = function(socket, io) {
socket.on('generateToken', function(ownerUser) {
store.generateToken(ownerUser.userId);
io.sockets.emit('userList', {
userMapByUserId: store.getUserList()
});
});
socket.on('deleteToken', function(token) {
store.deleteToken(token.userId, token.tokenValue);
io.sockets.emit('userList', {
userMapByUserId: store.getUserList()
});
});
};

所以,基本上我们可以让多个客户端向该服务器发送请求以添加/删除 token 。我需要担心同步和竞争条件吗?

最佳答案

我在您显示的代码中没有发现任何并发问题。

node.js 中的 Javascript 是单线程的,并通过事件队列工作。一个执行线程运行直到完成,然后 JS 引擎获取下一个等待运行的事件并运行该执行线程直到完成。因此,Javascript 中不存在抢占式并发,而您在使用线程的语言或情况中可能需要担心这种情况。

node.js 中仍有一些地方可能会出现并发问题。如果您在代码中使用异步操作(例如套接字或磁盘的异步 IO),则可能会发生这种情况。在这种情况下,您的执行线程将运行至完成,但您的异步操作仍在运行且尚未完成,并且尚未调用其回调。此时,可以处理其他一些事件并且可以运行其他代码。因此,如果您的异步回调引用的状态可能会被其他事件处理程序更改,那么您可能会遇到并发问题。

在您在问题中披露的两个套接字事件处理程序中,我在事件处理程序中运行的代码中没有看到任何异步回调。如果是这样的话,那么那里就没有并发的机会。即使存在并发机会,但单独的代码段没有使用/修改相同的基础数据,那么您仍然可以。

<小时/>

为了给您提供一个可能导致并发问题的示例,我有一个在 Raspberry Pi 上运行的 node.js 应用程序。每 10 秒它就会读取几个数字温度传感器,并将数据记录在内存数据结构中。每隔几个小时,它就会将数据写入磁盘。将数据写入磁盘的过程都是通过一系列异步磁盘 IO 操作完成的。每个异步磁盘 IO 操作都有一个回调,并且代码仅在该回调中继续(从技术上讲,我使用 Promise 来管理回调,但其概念相同)。这会产生并发问题,因为如果在我正在进行这些异步磁盘操作之一时记录新温度的计时器触发,那么数据结构可能会在将其写入磁盘的过程中发生变化,这可能会给我带来问题。

并不是说异步操作会在磁盘写入过程中被中断(node.js 不会以这种方式抢占),而是因为写入磁盘的整个操作由许多单独的异步文件组成写入时,可以在单独的异步文件写入之间处理其他事件。如果这些事件可能会扰乱您的数据,则可能会产生问题。

我的解决方案是在开始将数据写入磁盘时设置一个标志(然后在完成后清除该标志),如果我想在设置该标志时向数据结构添加一些内容,那么新数据将进入一个队列,稍后会被处理,因此当我将其写入磁盘时,核心数据结构没有改变。我能够通过几种用于修改数据的方法完全实现这一点,以便调用代码甚至不需要知道正在发生的任何不同情况。

<小时/>

尽管this answer是为浏览器中的 Ajax 编写的,事件队列概念与 Node.js 中的相同,因此您可能会发现它很有帮助。请注意,node.js 被称为“V8 Javascript 的事件 IO”是有原因的(因为它通过事件队列运行)。

关于javascript - Javascript 和 Socket.io 中的同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31665212/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com