使用 Node 的文件系统同步方法比使用相同的异步方法更好吗?
Is it ever better to use Node's filesystem sync methods over the same async methods?
这是一个性能问题,比什么都重要
Node 公开了三种不同类型的方法来完成各种文件系统任务:
- 承诺 API(异步)
- 回调API(异步)
- 同步API(同步)
我阅读的文章和 Whosebug 答案多得数不过来,所有这些都声称从不 需要同步方法。
我最近编写了一个脚本,如果它们不存在,则需要创建几个目录。在此期间,我注意到如果我使用 async/await 方法(主要是 fs.promises.mkdir
和 fs.promises.access
),事件循环将简单地继续到下一个异步代码位,而不管接下来的位需要这些目录。这是预期的行为,毕竟它是异步的。
我知道这可以通过一个很好的小回调地狱 sesh 来解决,但这不是问题,而承诺 api 可以用于所有其他方法的想法是。
那么问题就变成了:
使用 Node 的文件系统同步方法比使用相同的异步方法更好吗?
在这种情况下真的需要阻止进程吗?
或换句话说:
是否可以完全避免同步方法并仅使用承诺 api (不是承诺 + 回调)?
似乎使用同步方法(考虑到我上面的情况,在进行任何其他调用之前目录必须存在)对于编写可读、清晰的代码非常有用,即使它可能会产生负面影响性能。
话虽这么说,但有大量信息表明同步 api 完全没用,从不需要。
同样,这纯粹是为了迎合承诺 api。是的,回调和承诺都是异步的,但是作业和消息队列之间的差异使得两者 api 在这种情况下完全不同。
PS:对于示例的附加上下文,我提供了一个代码示例,因此您不必想象我的示例;)
谢谢! :)
// Checks if dir exists, if not, creates it. (not the actual code, just an example)
// Sync version
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
// Async version
try {
await fs.promises.access(dirPath);
} catch {
await fs.promises.mkdir(dirPath);
}
视情况而定。 sync 方法的主要优点是它们可以更轻松地使用其结果,主要缺点是它们会阻止所有其他代码在工作时执行。
如果您发现其他代码无法响应事件不是问题,您可能会认为使用同步方法是合理的 - 如果有问题的代码没有机会或运行 与其他任何事情并行的原因。
例如,您绝对不会想在内部使用同步方法,比如说,处理请求的服务器。
如果您的代码需要在脚本首次运行时读取一些配置文件(或创建一些文件夹),而这些配置文件数量不足以让并行性发挥作用,您可以考虑使用同步方法。
也就是说,即使您当前的实现不需要并行性,但要记住的一点是,如果情况发生变化并且您发现确实需要允许并行处理,那么您将不会有如果您首先使用 promise-based 方法开始,则对现有代码进行任何更改 - 如果您了解该语言,正确使用 Promises 应该非常容易,所以如果有机会的话,您可能会考虑使用 Promises。
这是一个性能问题,比什么都重要
Node 公开了三种不同类型的方法来完成各种文件系统任务:
- 承诺 API(异步)
- 回调API(异步)
- 同步API(同步)
我阅读的文章和 Whosebug 答案多得数不过来,所有这些都声称从不 需要同步方法。
我最近编写了一个脚本,如果它们不存在,则需要创建几个目录。在此期间,我注意到如果我使用 async/await 方法(主要是 fs.promises.mkdir
和 fs.promises.access
),事件循环将简单地继续到下一个异步代码位,而不管接下来的位需要这些目录。这是预期的行为,毕竟它是异步的。
我知道这可以通过一个很好的小回调地狱 sesh 来解决,但这不是问题,而承诺 api 可以用于所有其他方法的想法是。
那么问题就变成了:
使用 Node 的文件系统同步方法比使用相同的异步方法更好吗?
在这种情况下真的需要阻止进程吗?
或换句话说:
是否可以完全避免同步方法并仅使用承诺 api (不是承诺 + 回调)?
似乎使用同步方法(考虑到我上面的情况,在进行任何其他调用之前目录必须存在)对于编写可读、清晰的代码非常有用,即使它可能会产生负面影响性能。
话虽这么说,但有大量信息表明同步 api 完全没用,从不需要。
同样,这纯粹是为了迎合承诺 api。是的,回调和承诺都是异步的,但是作业和消息队列之间的差异使得两者 api 在这种情况下完全不同。
PS:对于示例的附加上下文,我提供了一个代码示例,因此您不必想象我的示例;)
谢谢! :)
// Checks if dir exists, if not, creates it. (not the actual code, just an example)
// Sync version
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
// Async version
try {
await fs.promises.access(dirPath);
} catch {
await fs.promises.mkdir(dirPath);
}
视情况而定。 sync 方法的主要优点是它们可以更轻松地使用其结果,主要缺点是它们会阻止所有其他代码在工作时执行。
如果您发现其他代码无法响应事件不是问题,您可能会认为使用同步方法是合理的 - 如果有问题的代码没有机会或运行 与其他任何事情并行的原因。
例如,您绝对不会想在内部使用同步方法,比如说,处理请求的服务器。
如果您的代码需要在脚本首次运行时读取一些配置文件(或创建一些文件夹),而这些配置文件数量不足以让并行性发挥作用,您可以考虑使用同步方法。
也就是说,即使您当前的实现不需要并行性,但要记住的一点是,如果情况发生变化并且您发现确实需要允许并行处理,那么您将不会有如果您首先使用 promise-based 方法开始,则对现有代码进行任何更改 - 如果您了解该语言,正确使用 Promises 应该非常容易,所以如果有机会的话,您可能会考虑使用 Promises。