node-js中的IO编写
IO writing in node-js
我有一个 node.js(语法实际上是 Typescript)应用程序:
- 在某些 HTTP 请求处理程序中,每天在文件中异步写入计数并
- 一个 cron 作业(在使用 node-cron 模块完成的节点应用程序内)在午夜重置该文件
非阻塞事件循环循环对我来说不是很清楚(it's not single thread 如果我做对了的话)我担心 cron 模块在我重置文件的情况下正在写信给它。
我需要担心吗?就像在我承诺的 fs.writeFile
写作时设置的全局标志一样?有没有更优雅的处理方式?
谢谢,如果这是一个愚蠢的问题,我们深表歉意。
这是我的代码的框架:
import * as fs from 'fs';
import * as path from 'path';
import { CronJob } from 'cron';
import { pfs } from './promisifiedFs';
const daily_file = '/path_to_my_file'
new CronJob('0 0 * * * *', function() {
fs.writeFileSync(daily_file, 0, {'flag': 'w'});
}, null, true);
// somewhere called inside an HTTP GET handler
async function doBill(data) {
const something = //....
const currentCountRaw = await pfs.readfilePromisified(daily_file, 'utf-8');
const currentCount = parseFloat(currentCountRaw) || 0;
await pfs.writeFilePromisified(daily_file, currentCount + something, {'flag': 'w'});
}
在 Node.js 中,您的代码 在单线程中运行。它是单线程的,除非您使用的是执行异步 I/O 的本机模块,这些模块恰好将工作加载到线程池(情况并非总是如此) 或 如果您使用 cluster 模块。
当您在脚本中使用 writeFileSync 时,主线程将阻塞,直到您完成该操作,并且不会并行执行任何其他操作。
编辑: 如评论中所述,有一种情况很可能发生:cron 作业在读取和写入之间运行。还有一种不太可能发生但可能发生的情况:异步写入已经 运行 并且 cronjob 运行。所以我恢复了我所说的,因为它是错误的,并且建议创建一个像变量或锁文件这样的互斥体。
我建议使用 async queue (if you are only running one instance of the node application) or lockfile 之类的东西(如果您打算集群或使用多个进程)。
这里有一些代码(我相信)会重复我上面概述的问题,通过编写 很多 更大的值,这应该会增加多次写入冲突的机会。
我的电脑似乎做的是接受 fs.writeFileSync
然后...什么都不做?我可能弄错了,但这是我正在使用的代码。我选择 co
而不是 async/await
以避免需要转译。
const fs = require('fs');
const co = require('co');
const crypto = require('crypto');
function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
function now() {
return new Date().toISOString();
}
function log(...args) {
return console.log(now(), ...args);
}
const file = './output.txt';
log('generating bytes...');
const bytes = crypto.randomBytes(100000000);
log('done generating bytes');
function writeAsync() {
return new Promise((resolve, reject) => {
return fs.writeFile(file, bytes.toString('base64'), { 'flag': 'w' }, err => {
if (err) {
return reject(err);
}
return resolve();
});
});
}
function writeSync() {
fs.writeFileSync(file, 'FINDMEFINDMEFINDME', { 'flag': 'w' });
}
function run() {
return co(function*() {
log('before write async');
const promise = writeAsync().then(() => log('after write async'));
const ms = 1;
log(`waiting for ${ms} ms`);
yield wait(ms);
log('done waiting');
log('before write sync');
writeSync();
log('after write sync');
yield promise;
});
}
run().catch(err => console.error(err));
示例输出:
2016-10-03T22:52:05.032Z generating bytes...
2016-10-03T22:52:06.846Z done generating bytes
2016-10-03T22:52:06.848Z before write async
2016-10-03T22:52:06.999Z waiting for 1 ms
2016-10-03T22:52:07.001Z done waiting
2016-10-03T22:52:07.001Z before write sync
2016-10-03T22:52:07.012Z after write sync
2016-10-03T22:52:08.623Z after write async
行为:
似乎 文件输出包含 writeAsync()
的结果,而 writeSync()
对输出没有影响。老实说,我有点期待会抛出一个错误。甚至可能 writeSync()
将 'FINDMEFINDMEFINDME'
放在其他代码的中间,但我无法在输出文件中找到该字符串。
我有一个 node.js(语法实际上是 Typescript)应用程序:
- 在某些 HTTP 请求处理程序中,每天在文件中异步写入计数并
- 一个 cron 作业(在使用 node-cron 模块完成的节点应用程序内)在午夜重置该文件
非阻塞事件循环循环对我来说不是很清楚(it's not single thread 如果我做对了的话)我担心 cron 模块在我重置文件的情况下正在写信给它。
我需要担心吗?就像在我承诺的 fs.writeFile
写作时设置的全局标志一样?有没有更优雅的处理方式?
谢谢,如果这是一个愚蠢的问题,我们深表歉意。
这是我的代码的框架:
import * as fs from 'fs';
import * as path from 'path';
import { CronJob } from 'cron';
import { pfs } from './promisifiedFs';
const daily_file = '/path_to_my_file'
new CronJob('0 0 * * * *', function() {
fs.writeFileSync(daily_file, 0, {'flag': 'w'});
}, null, true);
// somewhere called inside an HTTP GET handler
async function doBill(data) {
const something = //....
const currentCountRaw = await pfs.readfilePromisified(daily_file, 'utf-8');
const currentCount = parseFloat(currentCountRaw) || 0;
await pfs.writeFilePromisified(daily_file, currentCount + something, {'flag': 'w'});
}
在 Node.js 中,您的代码 在单线程中运行。它是单线程的,除非您使用的是执行异步 I/O 的本机模块,这些模块恰好将工作加载到线程池(情况并非总是如此) 或 如果您使用 cluster 模块。
当您在脚本中使用 writeFileSync 时,主线程将阻塞,直到您完成该操作,并且不会并行执行任何其他操作。
编辑: 如评论中所述,有一种情况很可能发生:cron 作业在读取和写入之间运行。还有一种不太可能发生但可能发生的情况:异步写入已经 运行 并且 cronjob 运行。所以我恢复了我所说的,因为它是错误的,并且建议创建一个像变量或锁文件这样的互斥体。
我建议使用 async queue (if you are only running one instance of the node application) or lockfile 之类的东西(如果您打算集群或使用多个进程)。
这里有一些代码(我相信)会重复我上面概述的问题,通过编写 很多 更大的值,这应该会增加多次写入冲突的机会。
我的电脑似乎做的是接受 fs.writeFileSync
然后...什么都不做?我可能弄错了,但这是我正在使用的代码。我选择 co
而不是 async/await
以避免需要转译。
const fs = require('fs');
const co = require('co');
const crypto = require('crypto');
function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
function now() {
return new Date().toISOString();
}
function log(...args) {
return console.log(now(), ...args);
}
const file = './output.txt';
log('generating bytes...');
const bytes = crypto.randomBytes(100000000);
log('done generating bytes');
function writeAsync() {
return new Promise((resolve, reject) => {
return fs.writeFile(file, bytes.toString('base64'), { 'flag': 'w' }, err => {
if (err) {
return reject(err);
}
return resolve();
});
});
}
function writeSync() {
fs.writeFileSync(file, 'FINDMEFINDMEFINDME', { 'flag': 'w' });
}
function run() {
return co(function*() {
log('before write async');
const promise = writeAsync().then(() => log('after write async'));
const ms = 1;
log(`waiting for ${ms} ms`);
yield wait(ms);
log('done waiting');
log('before write sync');
writeSync();
log('after write sync');
yield promise;
});
}
run().catch(err => console.error(err));
示例输出:
2016-10-03T22:52:05.032Z generating bytes...
2016-10-03T22:52:06.846Z done generating bytes
2016-10-03T22:52:06.848Z before write async
2016-10-03T22:52:06.999Z waiting for 1 ms
2016-10-03T22:52:07.001Z done waiting
2016-10-03T22:52:07.001Z before write sync
2016-10-03T22:52:07.012Z after write sync
2016-10-03T22:52:08.623Z after write async
行为:
似乎 文件输出包含 writeAsync()
的结果,而 writeSync()
对输出没有影响。老实说,我有点期待会抛出一个错误。甚至可能 writeSync()
将 'FINDMEFINDMEFINDME'
放在其他代码的中间,但我无法在输出文件中找到该字符串。