【问题标题】:IO writing in node-js在 node-js 中写入 IO
【发布时间】:2016-09-30 16:07:51
【问题描述】:

我有一个 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'});

}

【问题讨论】:

  • 您能否更具体地说明“重置”文件的含义?使用带有0'a' 标志的writeFileSync 将在每次运行文件时将0 附加到文件中,而带有'w' 标志的writeFilePromisified 将覆盖文件currentCount + something 中的任何内容。这是故意的吗?
  • @dvlsg 抱歉 a 是错字
  • 没问题,我认为是这样,但我不确定。所以这里的目标是你有一个从 0 开始的文件,随着时间的推移,这个数字会增加并被某个数字覆盖(因为我们不知道 something 发生了什么)每次doBill被调用,直到下一个 CronJob 运行?

标签: node.js concurrency io file-writing


【解决方案1】:

在 Node.js 中 您的代码 在单个线程中运行。它是单线程的,除非您使用的是执行异步 I/O 的本机模块,这些模块碰巧将工作负载到线程池(并非总是如此)如果您使用 cluster模块。

当您在脚本中使用 writeFileSync 时,主线程将阻塞,直到您完成此操作,并且不会并行执行其他任何操作。

编辑: 如 cmets 中所述,有一种可能发生的情况:cron 作业在读取和写入之间运行。还有另一种不太可能发生但可能发生的情况:异步写入已经在运行并且 cronjob 正在运行。所以我恢复了我所说的,因为它是错误的,并建议创建一个互斥锁,如变量或锁定文件。

【讨论】:

  • 你还没有回答这个问题:) .. cron 模块在我写文件时正在重置文件。我需要担心吗?...
  • no 您不必担心它,因为您在写入时 不会重置任何内容。这就是我试图用我的解释来传达的。
  • 感谢您的澄清。
  • 从技术上讲,您可以从异步文件写入开始,然后在异步文件写入在后台工作时尝试同步文件写入。
  • 这不太可能,但我同意这是可能的。仔细观察它也可能发生 - 而且更有可能 - 在读取和写入 cron 运行之间。鉴于创建锁定文件可能是一个安全的选择。
【解决方案2】:

我建议使用async queue(如果您只运行节点应用程序的一个实例)或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' 放在其他代码的中间,但我无法在输出文件中找到该字符串。

【讨论】:

    猜你喜欢
    • 2014-10-18
    • 2017-08-07
    • 2015-12-24
    • 1970-01-01
    • 2016-02-19
    • 2013-04-20
    • 2013-10-03
    • 1970-01-01
    • 2022-01-04
    相关资源
    最近更新 更多