简体   繁体   English

IO用node-js编写

[英]IO writing in node-js

I have a node.js (syntax is Typescript actually) application that: 我有一个node.js(语法实际上是Typescript)应用程序:

  • at some HTTP request handler asynchronously write in a file a daily count and 在某些HTTP请求处理程序中,异步将文件每日写入文件,
  • a cron job (inside the node application done with node-cron module) that at midnight reset that file 在午夜重置该文件的cron作业(在使用node-cron模块完成的节点应用程序内部)

The non-blocking event loop loop is not super clear to me ( it's not single thread under the hood if I got it right) and I'm worried about situation where the cron module is resetting the file while I'm writing to it. 非阻塞事件循环循环对我来说不是很清楚(如果我弄错的话, 它不是幕后的单线程 ),而且我担心cron模块在写入文件时会重置文件的情况。

Do I have to worry about it? 我需要担心吗? Like with a global flag that is set while my promisified fs.writeFile is writing? 就像在我承诺的fs.writeFile正在写入时设置的全局标志一样? Are there some more elegant way to handle it? 有没有更优雅的处理方式?

Thanks and sorry if it's a dumb question. 感谢和抱歉,如果这是一个愚蠢的问题。

This is a skeleton of my code: 这是我的代码的骨架:

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'});

}

In Node.js your code runs in a single thread. 在Node.js中, 您的代码在单个线程中运行。 It is single threaded unless you are using native modules that do asynchronous I/O that happen to load off work to the thread pool (which isn't always the case) or if you use the cluster module. 它是单线程的,除非您正在使用执行异步I / O的本机模块,而这些模块恰好将工作负载卸载到线程池中(并非总是如此), 或者如果您使用集群模块。

As you are using writeFileSync in your script the main thread will block until you are done doing that and will do nothing else in parallel. 当您在脚本中使用writeFileSync时,主线程将一直阻塞,直到您完成该操作为止,并且不会并行执行其他任何操作。

Edit: As noted in the comments there is a case that is probable to happen: The cron job runs between the read and the write. 编辑:如注释中所述,有可能发生以下情况:cron作业在读取和写入之间运行。 There is another case that is unlikely to happen but possible: The async write is already running and the cronjob runs. 还有另一种情况不太可能发生,但有可能发生:异步写入已在运行,并且cronjob运行。 So I revert what I said because it was wrong and would recommend creating a mutex like variable or a lock file. 因此,我恢复了我的说法,因为它是错误的,建议您创建一个互斥体,如变量或锁定文件。

I would suggest using something like async queue (if you are only running one instance of the node application) or lockfile (if you intend to cluster or use multiple processes). 我建议使用异步队列 (如果您仅运行节点应用程序的一个实例)或锁文件 (如果您打算集群或使用多个进程)之类的东西。

Here's some code which (I believe) will duplicate the issue I have outlined above, by writing much larger values which should increase the chance of a multiple write collision. 下面是一些代码(我相信)将复制我所上述,这个问题通过写这应该增加多写碰撞的机会更大价值。

What my computer seems to do is take the fs.writeFileSync and... do nothing with it? 我的计算机似乎要执行的操作是fs.writeFileSync然后…什么都不做? I could be mistaken, but here's the code I'm using. 我可能会误会,但这是我正在使用的代码。 I opted for co instead of async/await to avoid needing to transpile. 我选择使用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));

Example output: 输出示例:

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

Behavior: 行为:

It seems like the file output contains the result of writeAsync() and writeSync() has no effect on the output. 似乎文件输出包含writeAsync()的结果,而writeSync()对输出没有影响。 I sort of expected an error to be thrown, to be honest. 老实说,我有点希望抛出一个错误。 Maybe even writeSync() placing 'FINDMEFINDMEFINDME' in the middle of the other code, but I wasn't able to find that string in the output file. 甚至writeSync()'FINDMEFINDMEFINDME'放置在其他代码的中间,但是我无法在输出文件中找到该字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM